ToolDeck

رمزگشایی Base64 در Java — راهنمای getDecoder().decode()

·Backend Engineer·بررسی‌شده توسطAisha Osei·منتشر شده

از رمزگشایی Base64 آنلاین آنلاین رایگان مستقیم در مرورگرتان استفاده کنید — نیازی به نصب نیست.

امتحان کردن رمزگشایی Base64 آنلاین آنلاین ←

دیکد کردن Base64 در Java چیزی است که هر چند روز یک‌بار به آن نیاز پیدا می‌کنم — خواندن secret ها از متغیرهای محیطی Kubernetes، پردازش payload های باینری از REST API ها، بررسی توکن‌های JWT در طول debugging. کلاس داخلی java.util.Base64 جاوا (از JDK 8) سه نوع دیکودر ارائه می‌دهد: getDecoder() برای Base64 استاندارد، getUrlDecoder() برای ورودی URL-safe، و getMimeDecoder() برای داده‌های شکسته‌شده در خط مانند پیوست‌های ایمیل. برای بررسی سریع بدون نوشتن کد، دیکودر Base64 ToolDeck آن را فوری در مرورگر شما انجام می‌دهد. این راهنما برای Java 8+ است و هر سه دیکودر، استریمینگ با wrap(InputStream)، استخراج payload JWT، دیکد کردن فایل‌ها و پاسخ‌های API، Apache Commons Codec به‌عنوان جایگزین، و چهار اشتباه رایجی که خروجی خراب در محیط production تولید می‌کنند را پوشش می‌دهد.

  • Base64.getDecoder().decode(s) روش استاندارد است — در java.util.Base64 از JDK 8 به بعد وجود دارد و به هیچ وابستگی‌ای نیاز ندارد.
  • برای توکن‌های JWT و payload های OAuth از getUrlDecoder() استفاده کنید — آن‌ها از الفبای - و _ استفاده می‌کنند، نه + و /.
  • getMimeDecoder() شکست خط و فاصله را نادیده می‌گیرد و برای پیوست‌های ایمیل و گواهی‌نامه‌های PEM گزینه مناسبی است.
  • decoder.wrap(InputStream) برای فایل‌های بزرگ بدون بارگذاری همه چیز در حافظه، دیکد لایو انجام می‌دهد.
  • دیکودر پایه سختگیرانه است — newline های انتهایی، فاصله‌ها، یا کاراکترهای الفبای اشتباه فوراً IllegalArgumentException پرتاب می‌کنند.

دیکد کردن Base64 چیست؟

کدگذاری Base64 داده‌های باینری را به یک نمایش ASCII 64 کاراکتری تبدیل می‌کند تا بتوانند از طریق کانال‌های متنی — فیلدهای JSON، هدرهای HTTP، اسناد XML، بدنه ایمیل — به‌سلامت منتقل شوند. دیکد کردن این فرایند را معکوس می‌کند: هر ۴ کاراکتر Base64 به ۳ بایت اصلی بازمی‌گردند. پدینگ = در انتها نشان می‌دهد چند بایت برای پر کردن گروه آخر اضافه شده است. Base64 رمزگذاری نیست — هر کسی می‌تواند آن را معکوس کند. هدف آن سلامت انتقال است، نه محرمانگی.

سناریوهای رایج دیکد کردن در Java: استخراج مقادیر پیکربندی که به‌صورت متغیر محیطی Base64 تزریق شده‌اند، باز کردن بسته‌بندی محتوای باینری فایل از پاسخ‌های cloud API، خواندن گواهی‌نامه‌های PEM-encoded، و بررسی payload توکن‌های JWT در طول debugging.

After · text
Before · text
db-prod.us-east-1.amazonaws.com:5432
ZGItcHJvZC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbTo1NDMy

Base64.getDecoder().decode() — روش استاندارد دیکد کردن

کلاس java.util.Base64 در JDK 8 اضافه شد و جایگزین sun.misc.BASE64Decoder قدیمی که همه به آن متکی بودند شد. هیچ وابستگی خارجی لازم نیست — فقط import java.util.Base64 کرده و Base64.getDecoder().decode() را فراخوانی کنید. این متد یا یک String یا یک byte[] می‌پذیرد و یک byte[] از داده‌های دیکدشده برمی‌گرداند.

یک مثال ساده

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class DecodeCredential {
    public static void main(String[] args) {
        // Kubernetes secret value, Base64-encoded
        String encoded = "ZGItcHJvZC51cy1lYXN0LTEuYW1hem9uYXdzLmNvbTo1NDMy";

        byte[] decodedBytes = Base64.getDecoder().decode(encoded);
        String connectionString = new String(decodedBytes, StandardCharsets.UTF_8);

        System.out.println(connectionString);
        // db-prod.us-east-1.amazonaws.com:5432
    }
}

همیشه هنگام ساخت String مقدار StandardCharsets.UTF_8 را مشخص کنید. سازنده بدون آرگومان new String(bytes) از کدگذاری پیش‌فرض پلتفرم استفاده می‌کند که بین سیستم‌ها متفاوت است. روی یک سرور Windows با Cp1252 به‌عنوان پیش‌فرض، کاراکترهای UTF-8 چندبایتی به‌آرامی خراب می‌شوند.

تست رفت‌وبرگشت

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class RoundTrip {
    public static void main(String[] args) {
        String original = "redis://cache-prod.internal:6379/session-store";

        String encoded = Base64.getEncoder().encodeToString(
            original.getBytes(StandardCharsets.UTF_8)
        );
        System.out.println(encoded);
        // cmVkaXM6Ly9jYWNoZS1wcm9kLmludGVybmFsOjYzNzkvc2Vzc2lvbi1zdG9yZQ==

        byte[] decoded = Base64.getDecoder().decode(encoded);
        String recovered = new String(decoded, StandardCharsets.UTF_8);

        System.out.println(recovered.equals(original)); // true
    }
}

دیکد مستقیم به بافر

overload با سه آرگومان decode(byte[] src, byte[] dst) مستقیماً به یک بافر مقصد می‌نویسد و تعداد بایت‌های نوشته‌شده را برمی‌گرداند. این کار یک allocation اضافی در مسیرهای پر ترافیک را حذف می‌کند:

Java 8+
import java.util.Base64;

public class DecodeToBuffer {
    public static void main(String[] args) {
        byte[] src = "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=".getBytes();
        byte[] dst = new byte[1024]; // pre-allocated

        int len = Base64.getDecoder().decode(src, dst);
        String result = new String(dst, 0, len);

        System.out.println(result);
        // {"host":"10.0.1.50","port":8443}
    }
}
توجه:decode() یک IllegalArgumentException پرتاب می‌کند اگر ورودی شامل کاراکترهایی خارج از الفبای Base64 (از جمله شکست خط و فاصله) باشد. اگر ورودی شما ممکن است فاصله داشته باشد، به getMimeDecoder() سوئیچ کنید یا قبل از دیکد با encoded.strip() آن را پاکسازی کنید.

دیکد کردن Base64 با انواع غیراستاندارد و اشیاء سفارشی

byte[] خام از decode() اغلب باید به چیز خاص‌تری تبدیل شود: یک UUID، یک شیء جاوای سریالیز شده، یک پیام protobuf، یا یک timestamp. دیکودر همیشه بایت برمی‌گرداند — تبدیل به انواع domain مسئولیت شماست.

Base64 به UUID

Java 8+
import java.util.Base64;
import java.nio.ByteBuffer;
import java.util.UUID;

public class DecodeUUID {
    public static UUID fromBase64(String encoded) {
        byte[] bytes = Base64.getUrlDecoder().decode(encoded);
        ByteBuffer bb = ByteBuffer.wrap(bytes);
        return new UUID(bb.getLong(), bb.getLong());
    }

    public static void main(String[] args) {
        // Compact Base64-encoded UUID from an API response
        String encoded = "f47ac10b-58cc-4372-a567-0e02b2c3d479";
        UUID original = UUID.fromString(encoded);

        // Encode to Base64 (compact form — 22 chars vs 36)
        ByteBuffer bb = ByteBuffer.wrap(new byte[16]);
        bb.putLong(original.getMostSignificantBits());
        bb.putLong(original.getLeastSignificantBits());
        String compact = Base64.getUrlEncoder().withoutPadding()
            .encodeToString(bb.array());
        System.out.println(compact); // 9HrBC1jMQ3KlZw4CssPUeQ

        // Decode back
        UUID recovered = fromBase64(compact);
        System.out.println(recovered); // f47ac10b-58cc-4372-a567-0e02b2c3d479
    }
}

Base64 به شیء JSON دسریالیزشده با Jackson

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.time.Instant;

public class DecodeJsonPayload {
    record DeployEvent(String service, String region, Instant deployedAt, int replicas) {}

    public static void main(String[] args) throws Exception {
        // Base64-encoded JSON payload from a message queue
        String encoded = "eyJzZXJ2aWNlIjoicGF5bWVudC1nYXRld2F5Iiwi"
            + "cmVnaW9uIjoiZXUtd2VzdC0xIiwiZGVwbG95ZWRBdCI6"
            + "IjIwMjYtMDMtMTVUMTQ6MzA6MDBaIiwicmVwbGljYXMiOjR9";

        byte[] jsonBytes = Base64.getDecoder().decode(encoded);
        String json = new String(jsonBytes, StandardCharsets.UTF_8);
        System.out.println(json);
        // {"service":"payment-gateway","region":"eu-west-1",
        //  "deployedAt":"2026-03-15T14:30:00Z","replicas":4}

        ObjectMapper mapper = new ObjectMapper();
        mapper.findAndRegisterModules(); // picks up JavaTimeModule
        DeployEvent event = mapper.readValue(jsonBytes, DeployEvent.class);

        System.out.println(event.service());   // payment-gateway
        System.out.println(event.deployedAt()); // 2026-03-15T14:30:00Z
    }
}
هشدار:هرگز از ObjectInputStream برای دسریالیز کردن داده‌های Base64 غیرمعتمد استفاده نکنید. حملات deserialization جاوا کاملاً مستند شده‌اند — اگر محتوای کدگذاری‌شده از یک منبع خارجی می‌آید، به‌جای استفاده از سریالیزاسیون native جاوا، آن را به‌صورت JSON یا protobuf تجزیه کنید.

مرجع متدهای Base64.Decoder

تمام متدها به java.util.Base64 و کلاس داخلی آن Base64.Decoder تعلق دارند. سه متد factory روی Base64 نمونه‌های دیکودر مختلفی برمی‌گردانند؛ متدهای decode() و wrap() روی نمونه Decoder هستند.

متد
مقدار بازگشتی
نوع ورودی
توضیح
getDecoder()
Base64.Decoder
دیکودر استاندارد (RFC 4648 §4، الفبای + و / با پدینگ =)
getUrlDecoder()
Base64.Decoder
دیکودر URL-safe (RFC 4648 §5، الفبای - و _ با پدینگ =)
getMimeDecoder()
Base64.Decoder
دیکودر MIME — جداکننده‌های خط و کاراکترهای غیر Base64 را نادیده می‌گیرد
decode(String src)
byte[]
String
رشته ورودی را به یک آرایه بایت جدید دیکد می‌کند
decode(byte[] src)
byte[]
byte[]
آرایه بایت ورودی را به یک آرایه بایت جدید دیکد می‌کند
decode(byte[] src, byte[] dst)
int
byte[] + byte[]
به بافر dst از پیش تخصیص‌یافته دیکد می‌کند و تعداد بایت‌های نوشته‌شده را برمی‌گرداند
wrap(InputStream is)
InputStream
InputStream
یک استریم برمی‌گرداند که داده‌های Base64 را به‌صورت لایو دیکد می‌کند

getMimeDecoder() — دیکد کردن Base64 شکسته‌شده در خط و MIME

دیکودر پایه هر چیزی خارج از الفبای Base64 را رد می‌کند — و این شامل شکست‌های خط \r\n می‌شود که محتوای MIME-encoded همیشه دارد. پیوست‌های ایمیل، گواهی‌نامه‌های PEM، و برخی پاسخ‌های قدیمی API خروجی Base64 را در ۷۶ کاراکتر در هر خط می‌شکنند. getMimeDecoder() جداکننده‌های خط و هر کاراکتری که در الفبای Base64 نیست را بدون مشکل نادیده می‌گیرد، بنابراین این حالت را out of the box مدیریت می‌کند.

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class MimeDecode {
    public static void main(String[] args) {
        // PEM certificate body — line-wrapped at 76 characters
        String pemBody = "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0t\r\n"
            + "TUlJQm96Q0NBVWlnQXdJQkFnSUpBSXBhVDJU\r\n"
            + "aVFvZU1BMEdDU3FHU0liM0RRRU==";

        // getDecoder() would throw IllegalArgumentException here
        byte[] decoded = Base64.getMimeDecoder().decode(pemBody);
        System.out.println(new String(decoded, StandardCharsets.UTF_8));
        // -----BEGIN CERTIFICATE-----
        // MIIBozCCAUigAwIBAgIJAIpaT2T...
    }
}
توجه:getMimeDecoder() منعطف است: به‌جای پرتاب exception از روی کاراکترهای نامعتبر عبور می‌کند. این برای داده‌های MIME شناخته‌شده مناسب است، اما می‌تواند خرابی را در ورودی دلخواه به‌آرامی ببلعد. وقتی می‌خواهید اعتبارسنجی دقیق داشته باشید از getDecoder() استفاده کنید.

دیکد کردن Base64 از فایل و پاسخ API

خواندن یک فایل Base64-encoded از دیسک

فایل‌های باینری (تصاویر، گواهی‌نامه‌ها، blob های رمزگذاری‌شده) گاهی به‌صورت متن Base64 روی دیسک ذخیره می‌شوند. فایل را بخوانید، دیکد کنید، خروجی باینری را بنویسید:

Java 8+
import java.util.Base64;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public class DecodeFile {
    public static void main(String[] args) {
        Path inputPath = Path.of("tls-cert.pem.b64");
        Path outputPath = Path.of("tls-cert.pem");

        try {
            String encoded = Files.readString(inputPath).strip();
            byte[] decoded = Base64.getMimeDecoder().decode(encoded);
            Files.write(outputPath, decoded);

            System.out.printf("Decoded %d bytes → %s%n", decoded.length, outputPath);
        } catch (IOException e) {
            System.err.println("File error: " + e.getMessage());
        } catch (IllegalArgumentException e) {
            System.err.println("Invalid Base64: " + e.getMessage());
        }
    }
}

دیکد کردن یک فیلد Base64 از پاسخ HTTP API

API های ابری (AWS KMS، GitHub Contents، Vault) اغلب داده‌های باینری را به‌صورت رشته‌های Base64 داخل JSON برمی‌گردانند. ابتدا JSON را parse کنید، سپس فیلد هدف را دیکد کنید:

Java 11+
import java.util.Base64;
import java.nio.charset.StandardCharsets;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.net.URI;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class DecodeApiResponse {
    public static void main(String[] args) {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
            .uri(URI.create("https://api.example.com/secrets/db-password"))
            .header("Authorization", "Bearer sk-prod-9f8e7d6c")
            .build();

        try {
            HttpResponse<String> response = client.send(
                request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() != 200) {
                System.err.printf("Unexpected status: %d%n", response.statusCode());
                return;
            }

            ObjectMapper mapper = new ObjectMapper();
            JsonNode root = mapper.readTree(response.body());

            // API returns: {"name":"db-password","value":"cG9zdGdyZXM6eGs5...","version":3}
            String encodedValue = root.get("value").asText();
            byte[] decoded = Base64.getDecoder().decode(encodedValue);
            String secret = new String(decoded, StandardCharsets.UTF_8);

            System.out.println("Secret: " + secret);
            // Secret: postgres:xk9mP2qR@db-prod:5432/orders
        } catch (Exception e) {
            System.err.println("Failed to fetch secret: " + e.getMessage());
        }
    }
}
توجه:فراخوانی decode را در try-catch جداگانه‌ای برای IllegalArgumentException جدا از خطاهای شبکه قرار دهید. ترکیب کردن exception های I/O با خرابی‌های دیکد کردن debugging را سخت‌تر می‌کند — می‌خواهید سریع بفهمید مشکل از سمت API بوده یا شبکه.

دیکد کردن Base64 از خط فرمان

همیشه به یک برنامه جاوا نیاز ندارید. هر سیستم Linux و macOS دستور base64 دارد، و JDK 9+ با jshell برای one-liner های تعاملی جاوا ارائه می‌شود. برای بازرسی سریع در طول debugging، اینها از کامپایل یک کلاس سریع‌ترند.

bash
# Decode a Base64 string (Linux / macOS)
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode
# {"host":"10.0.1.50","port":8443}

# Decode and pretty-print with jq
echo "eyJob3N0IjoiMTAuMC4xLjUwIiwicG9ydCI6ODQ0M30=" | base64 --decode | jq .
# {
#   "host": "10.0.1.50",
#   "port": 8443
# }

# Quick decode with jshell (JDK 9+)
echo 'System.out.println(new String(java.util.Base64.getDecoder().decode("c2VydmVyLWNvbmZpZw==")))' | jshell -
# server-config

# macOS uses -D instead of --decode
echo "c2VydmVyLWNvbmZpZw==" | base64 -D

برای paste کردن مستقیم رشته‌های encoded در مرورگر، دیکودر Base64 ToolDeck هم نوع استاندارد و هم URL-safe را بدون هیچ راه‌اندازی مدیریت می‌کند.

جایگزین پرکارایی: Apache Commons Codec

java.util.Base64 داخلی جاوا از قبل بهینه‌سازی شده است — JDK 11+ از intrinsics روی x86 برای کدگذاری و دیکد کردن استفاده می‌کند. برای بیشتر برنامه‌ها، دلیلی برای رفتن سراغ یک کتابخانه شخص ثالث وجود ندارد. با این حال، Apache Commons Codec در codebases قدیمی محبوب است و Base64InputStream را برای دیکد استریمینگ با مدیریت خودکار whitespace ارائه می‌دهد.

XML (Maven)
<!-- pom.xml -->
<dependency>
    <groupId>commons-codec</groupId>
    <artifactId>commons-codec</artifactId>
    <version>1.17.0</version>
</dependency>
Java 8+
import org.apache.commons.codec.binary.Base64;

public class CommonsCodecDecode {
    public static void main(String[] args) {
        // Commons Codec is more lenient — handles whitespace and line breaks
        String encoded = "eyJob3N0IjoiMTAuMC4xLjUw\nIiwicG9ydCI6ODQ0M30=";
        byte[] decoded = Base64.decodeBase64(encoded);

        System.out.println(new String(decoded));
        // {"host":"10.0.1.50","port":8443}
    }
}

مزیت اصلی Commons Codec نسبت به API داخلی، انعطاف آن با whitespace به‌طور پیش‌فرض و کلاس Base64InputStream آن است که از decoder.wrap() جاوا قدیمی‌تر است. اگر روی Java 8+ هستید، API داخلی همه چیزی را که Commons Codec انجام می‌دهد پوشش می‌دهد. تنها زمانی سراغ Commons Codec می‌روم که پروژه از قبل به آن وابسته است.

استریمینگ فایل‌های بزرگ Base64 با decoder.wrap()

بارگذاری یک فایل Base64 با حجم ۲۰۰ مگابایت با Files.readString() و سپس فراخوانی decode() تقریباً ۳۵۰ مگابایت heap تخصیص می‌دهد: رشته encoded به علاوه آرایه بایت decoded. decoder.wrap(InputStream) به‌صورت لایو دیکد می‌کند و مصرف حافظه را ثابت نگه می‌دارد.

Java 8+
import java.util.Base64;
import java.io.*;
import java.nio.file.*;

public class StreamDecode {
    public static void main(String[] args) throws IOException {
        Path src = Path.of("database-dump.sql.b64");
        Path dst = Path.of("database-dump.sql");

        try (InputStream in = Base64.getMimeDecoder().wrap(
                 new BufferedInputStream(Files.newInputStream(src)));
             OutputStream out = new BufferedOutputStream(Files.newOutputStream(dst))) {

            byte[] buffer = new byte[8192];
            int bytesRead;
            long total = 0;
            while ((bytesRead = in.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
                total += bytesRead;
            }
            System.out.printf("Decoded %d bytes → %s%n", total, dst);
        }
    }
}

در Java 9+ می‌توانید حلقه خواندن را با in.transferTo(out) جایگزین کنید — همان کار را با کد کمتر انجام می‌دهد. اگر فایل ممکن است دارای شکست خط باشد (فایل‌های PEM، خروجی‌های ایمیل) از getMimeDecoder().wrap() به‌جای getDecoder().wrap() استفاده کنید.

Java 9+
import java.util.Base64;
import java.io.*;
import java.nio.file.*;

public class StreamDecodeSimple {
    public static void main(String[] args) throws IOException {
        try (InputStream in = Base64.getMimeDecoder().wrap(
                 new BufferedInputStream(Files.newInputStream(Path.of("backup.tar.b64"))));
             OutputStream out = Files.newOutputStream(Path.of("backup.tar"))) {
            in.transferTo(out); // Java 9+
        }
    }
}
هشدار:getDecoder().wrap() شکست خط در استریم را تحمل نمی‌کند. اگر داده‌های Base64 دارای newline هستند (شکسته‌شده در ۷۶ کاراکتر)، به‌جای آن از getMimeDecoder().wrap() استفاده کنید — در غیر این صورت استریم به‌آرامی خروجی خراب تولید می‌کند یا در جای نامعلومی exception پرتاب می‌کند.

دیکد کردن payload JWT در Java بدون کتابخانه JWT

یک JWT سه بخش Base64url-encoded است که با نقطه به هم متصل شده‌اند. بخش میانی payload است — قسمتی که در طول debugging به آن اهمیت می‌دهید. می‌توانید آن را بدون import کردن jjwt یا Nimbus دیکد کنید. روی . تقسیم کنید، بخش دوم را با getUrlDecoder() دیکد کنید، و JSON حاصل را parse کنید:

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

public class JWTInspect {
    public static String decodeJwtPayload(String token) {
        String[] parts = token.split("\\.");
        if (parts.length != 3) {
            throw new IllegalArgumentException(
                "Invalid JWT: expected 3 segments, got " + parts.length);
        }
        // JWT uses URL-safe Base64 without padding
        byte[] payload = Base64.getUrlDecoder().decode(parts[1]);
        return new String(payload, StandardCharsets.UTF_8);
    }

    public static void main(String[] args) {
        String token = "eyJhbGciOiJSUzI1NiJ9"
            + ".eyJzdWIiOiJ1c3ItNjcyIiwiaXNzIjoiYXV0aC5leGFtcGxlLmNvbSIs"
            + "ImV4cCI6MTc0MTk1NjgwMCwicm9sZXMiOlsiYWRtaW4iLCJiaWxsaW5nIl19"
            + ".SIGNATURE_PLACEHOLDER";

        String payload = decodeJwtPayload(token);
        System.out.println(payload);
        // {"sub":"usr-672","iss":"auth.example.com",
        //  "exp":1741956800,"roles":["admin","billing"]}
    }
}

اشتباهات رایج

در code review ها به هر یک از اینها برخورده‌ام، و دو مورد اول بخش عمده باگ‌های مرتبط با Base64 در محیط production سرویس‌های جاوا را تشکیل می‌دهند.

استفاده از getDecoder() روی ورودی URL-safe

مشکل: توکن‌های JWT و access token های OAuth از الفبای URL-safe (- و _) استفاده می‌کنند. پاس دادن آن‌ها به getDecoder() یک IllegalArgumentException پرتاب می‌کند زیرا - در الفبای Base64 استاندارد نیست.

راه‌حل: منبع داده خود را بررسی کنید: توکن‌های سیستم‌های احراز هویت به getUrlDecoder() نیاز دارند؛ پیوست‌های MIME به getMimeDecoder() نیاز دارند.

After · Java
Before · Java
String header = "eyJhbGciOiJSUzI1NiJ9";
byte[] decoded = Base64.getUrlDecoder().decode(header);
System.out.println(new String(decoded));
// {"alg":"RS256"}
// JWT header — URL-safe, no padding
String header = "eyJhbGciOiJSUzI1NiJ9";
byte[] decoded = Base64.getDecoder().decode(header);
// IllegalArgumentException: Illegal base64 character 2d
عدم مشخص کردن charset هنگام ساخت String

مشکل: new String(bytes) از charset پیش‌فرض JVM استفاده می‌کند که بین محیط‌ها متفاوت است. یک سرور Linux CI (UTF-8) و یک هاست Windows production (Cp1252) برای همان بایت‌ها نتایج متفاوتی تولید می‌کنند.

راه‌حل: همیشه StandardCharsets.UTF_8 را به‌عنوان آرگومان دوم پاس دهید.

After · Java
Before · Java
byte[] decoded = Base64.getDecoder().decode(encoded);
String result = new String(decoded, StandardCharsets.UTF_8);
// consistent across all platforms
byte[] decoded = Base64.getDecoder().decode(encoded);
String result = new String(decoded);
// platform-dependent — may corrupt multi-byte characters
دیکد کردن رشته‌ای با whitespace انتهایی

مشکل: رشته‌های Base64 که از ترمینال paste می‌شوند یا از فایل‌های config خوانده می‌شوند اغلب دارای newline انتهایی هستند. دیکودر پایه هر کاراکتری خارج از الفبای Base64 را رد می‌کند.

راه‌حل: قبل از دیکد .strip() را روی ورودی فراخوانی کنید، یا به getMimeDecoder() سوئیچ کنید که whitespace را نادیده می‌گیرد.

After · Java
Before · Java
String encoded = System.getenv("DB_PASSWORD_B64");
byte[] decoded = Base64.getDecoder().decode(encoded.strip());
System.out.println(new String(decoded, StandardCharsets.UTF_8));
// postgres
// Read from environment variable — has a trailing newline
String encoded = System.getenv("DB_PASSWORD_B64"); // "cG9zdGdyZXM=
"
byte[] decoded = Base64.getDecoder().decode(encoded);
// IllegalArgumentException: Illegal base64 character a
تبدیل داده‌های باینری به String

مشکل: فراخوانی new String(decoded) روی محتوای باینری (تصاویر، protobuf، blob های رمزگذاری‌شده) یک String نامعتبر تولید می‌کند. تبدیل آن به بایت بعداً به‌آرامی داده را خراب می‌کند زیرا سازنده String دنباله‌های نامعتبر UTF-8 را جایگزین می‌کند.

راه‌حل: داده‌های باینری را در تمام pipeline خود به‌صورت byte[] نگه دارید. تنها زمانی به String تبدیل کنید که مطمئن هستید محتوا متن است.

After · Java
Before · Java
byte[] decoded = Base64.getDecoder().decode(pngBase64);
// Write bytes directly — no String conversion
Files.write(Path.of("image.png"), decoded);
byte[] decoded = Base64.getDecoder().decode(pngBase64);
String imageStr = new String(decoded); // corrupts binary
Files.writeString(Path.of("image.png"), imageStr); // broken file

مقایسه متدها

دیکودرهای داخلی اکثر موارد استفاده را پوشش می‌دهند. Apache Commons Codec و Guava جایگزین‌هایی هستند که ممکن است در codebases قدیمی‌تر با آن‌ها مواجه شوید.

متد
نوع کدگذاری
فضای خالی را نادیده می‌گیرد
استریمینگ
انواع سفارشی
نیاز به نصب
Base64.getDecoder()
استاندارد (+, /)
خیر (JDK 8+)
Base64.getUrlDecoder()
URL-safe (-, _)
خیر (JDK 8+)
Base64.getMimeDecoder()
MIME (شکست خط مجاز)
خیر (JDK 8+)
decoder.wrap(InputStream)
هر نوع
بستگی به دیکودر دارد
خیر (JDK 8+)
Apache Commons Base64InputStream
استاندارد / URL-safe
بله (commons-codec)
Apache Commons Base64.decodeBase64()
استاندارد
بله (commons-codec)
Guava BaseEncoding.base64().decode()
استاندارد
بله (guava)

برای توکن‌های JWT و payload های API مدرن: getUrlDecoder(). برای پیوست‌های ایمیل و گواهی‌نامه‌های PEM: getMimeDecoder(). برای فایل‌های بزرگ که حافظه اهمیت دارد: decoder.wrap(InputStream). همه چیز دیگر: getDecoder(). Apache Commons Codec تنها زمانی منطقی است که از قبل در درخت وابستگی شما باشد.

برای تأیید سریع در طول توسعه، دیکودر Base64 آنلاین از نوشتن یک کلاس one-off سریع‌تر است.

سوالات متداول

چطور یک رشته Base64 را در Java دیکد کنم؟

java.util.Base64 را import کرده و Base64.getDecoder().decode(encodedString) را فراخوانی کنید. این متد یک byte[] برمی‌گرداند — برای دریافت متن خوانا آن را با new String(bytes, StandardCharsets.UTF_8) تبدیل کنید. برای Base64 URL-safe (که در JWTها استفاده می‌شود)، getDecoder() را با getUrlDecoder() جایگزین کنید.

Java 8+
import java.util.Base64;
import java.nio.charset.StandardCharsets;

byte[] decoded = Base64.getDecoder().decode("c2VydmVyLWNvbmZpZw==");
String result = new String(decoded, StandardCharsets.UTF_8);
System.out.println(result); // server-config

تفاوت بین getDecoder() و getMimeDecoder() در Java چیست؟

getDecoder() سختگیرانه عمل می‌کند — هر کاراکتری خارج از الفبای Base64، از جمله شکست خط، را رد می‌کند. getMimeDecoder() جداکننده‌های خط (\r\n) را تحمل می‌کند و هر کاراکتر غیر Base64 را نادیده می‌گیرد، بنابراین برای دیکد کردن پیوست‌های ایمیل و گواهی‌نامه‌های PEM که داده در آن‌ها در ۷۶ کاراکتر شکسته شده، گزینه مناسبی است.

Java 8+
String wrapped = "c2VydmVyLWNv\r\nbmZpZw==";

// getDecoder() throws IllegalArgumentException
// Base64.getDecoder().decode(wrapped); // FAILS

// getMimeDecoder() handles it
byte[] decoded = Base64.getMimeDecoder().decode(wrapped);
System.out.println(new String(decoded)); // server-config

چطور یک رشته Base64 URL-safe را در Java دیکد کنم؟

از Base64.getUrlDecoder().decode(encoded) استفاده کنید. دیکودر URL انتظار دارد الفبای - و _ تعریف‌شده در RFC 4648 §5 به‌جای + و / باشد. توکن‌های JWT همیشه از این الفبا استفاده می‌کنند. اگر کاراکترهای پدینگ (=) حذف شده باشند (که در JWTها رایج است)، دیکودر URL آن را مدیریت می‌کند — دیکودر URL جاوا هم ورودی با پدینگ و هم بدون پدینگ را می‌پذیرد.

Java 8+
import java.util.Base64;

// JWT header — URL-safe, no padding
String jwtHeader = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
byte[] decoded = Base64.getUrlDecoder().decode(jwtHeader);
System.out.println(new String(decoded));
// {"alg":"HS256","typ":"JWT"}

چطور یک فایل Base64 بزرگ را به‌صورت استریم در Java دیکد کنم؟

از decoder.wrap(inputStream) برای پوشاندن یک FileInputStream استفاده کنید. InputStream بازگشتی Base64 را به‌صورت لایو در هنگام خواندن بایت‌ها دیکد می‌کند، بنابراین مصرف حافظه صرف‌نظر از اندازه فایل ثابت می‌ماند. آن را از طریق یک BufferedInputStream یا مستقیم به Files.copy() هدایت کنید تا بهترین توان عملیاتی داشته باشید.

Java 8+
import java.util.Base64;
import java.io.*;
import java.nio.file.*;

try (InputStream in = Base64.getDecoder().wrap(
        new BufferedInputStream(new FileInputStream("payload.b64")));
     OutputStream out = new FileOutputStream("payload.bin")) {
    in.transferTo(out);
}

چرا Base64.getDecoder().decode() خطای IllegalArgumentException می‌دهد؟

دیکودر پایه سختگیرانه است: شکست خط، فاصله، و هر کاراکتری خارج از A-Za-z0-9+/= را رد می‌کند. سه دلیل رایج: ورودی دارای newline انتهایی است (آن را trim کنید)، ورودی از کاراکترهای URL-safe مانند - و _ استفاده می‌کند (به getUrlDecoder() سوئیچ کنید)، یا ورودی در ۷۶ کاراکتر شکسته شده است (به getMimeDecoder() سوئیچ کنید). اگر پیام خطا مبهم بود، بایت‌های خام را بررسی کنید.

Java 8+
String raw = "c2VydmVyLWNvbmZpZw==\n"; // trailing newline

// Option 1: trim whitespace
byte[] decoded = Base64.getDecoder().decode(raw.strip());

// Option 2: use MIME decoder which ignores whitespace
byte[] decoded2 = Base64.getMimeDecoder().decode(raw);

آیا می‌توانم بدون java.util.Base64 در Java دیکد کنم؟

بله، اما در Java 8+ دلیل خوبی برای این کار وجود ندارد. قبل از Java 8، توسعه‌دهندگان از sun.misc.BASE64Decoder (داخلی، در Java 9+ حذف شد)، javax.xml.bind.DatatypeConverter.parseBase64Binary() (در Java 11 حذف شد)، یا Apache Commons Codec استفاده می‌کردند. هر سه یا منسوخ شده‌اند یا به وابستگی اضافی نیاز دارند. از java.util.Base64 استفاده کنید — سریع‌تر است، با JDK عرضه می‌شود، و هر سه نوع (basic، URL-safe، MIME) را پوشش می‌دهد.

ابزارهای مرتبط

  • رمزگذار Base64 — متن یا داده‌های باینری را در مرورگر به Base64 کدگذاری کنید، برای تولید test fixture جهت paste کردن در unit test های جاوا مناسب است.
  • دیکودر JWT — هر سه بخش JWT را یک‌دفعه تقسیم و دیکد کنید، با بررسی فیلد به فیلد payload — وقتی فقط می‌خواهید یک توکن بخوانید از نوشتن یک کلاس جاوا سریع‌تر است.
  • دیکودر URL — رشته‌های URL-encoded را percent-decode کنید، مفید است وقتی پاسخ‌های API داده‌های Base64url را با پارامترهای query percent-encoded ترکیب می‌کنند.
  • قالب‌بندی JSON — پس از دیکد کردن یک payload JWT یا config API به‌صورت Base64، JSON را اینجا paste کنید تا ساختار آن را pretty-print و اعتبارسنجی کنید.
همچنین موجود در:GoC#
PN
Pavel NovakBackend Engineer

Pavel is a backend engineer with deep roots in the JVM ecosystem, working primarily with Java and Kotlin. He has extensive experience building data-intensive services and integrating third-party APIs at scale. He writes about modern Java features, the Jackson ecosystem, serialisation patterns, and practical approaches to keeping large codebases maintainable.

AO
Aisha Oseiبازبین فنی

Aisha is a Java engineer specialising in application security, Spring Security, and API design. She has worked on identity and access management systems, OAuth 2.0 integrations, and microservice security at scale. She writes about secure Java coding practices, token validation, cryptographic utilities, and the Spring ecosystem from a security-first perspective.