Java Tips | 基本ユーティリティ:Base64エンコード

Java Java
スポンサーリンク

Base64エンコードは「バイナリを文字の世界に連れてくる」技

業務システムでは、画像・PDF・バイナリデータを「そのままでは扱いにくい場所」に載せたい場面がよくあります。
例えば、JSON のフィールドに画像を入れたい、メールの本文に添付相当のデータを埋め込みたい、設定ファイルに秘密鍵を文字列として書きたい、などです。

ここで活躍するのが Base64 エンコードです。
Base64 は「バイナリデータを、ASCII だけで表現できる安全な文字列に変換する」仕組みで、Java では標準ライブラリだけで簡単に扱えます。


Base64 のざっくりしたイメージをつかむ

「中身は変わらないが、形だけ“文字列”になる」

Base64 エンコードは、データの意味を変えるものではありません。
圧縮でも暗号化でもなく、「0/1 の列を、A〜Z、a〜z、0〜9、+、/ などの文字にマッピングし直しているだけ」です。

例えば、「Hello」という文字列を UTF-8 バイト列にすると、48 65 6C 6C 6F という 16進数のバイト列になります。
これを Base64 にすると、SGVsbG8= という文字列になります。
元のデータは変わっておらず、「表現の仕方だけが“バイナリ → 文字列”に変わった」と考えるとイメージしやすいです。

この「どんなバイナリでも、テキストとして安全に運べる形にする」という性質が、
JSON・XML・メール・ログなど「バイナリがそのまま載せづらい世界」でとても重宝します。


Java 標準の Base64 ユーティリティを押さえる

java.util.Base64 を使うのが基本

Java 8 以降では、java.util.Base64 クラスが標準で用意されています。
これをそのまま使ってもよいのですが、業務コードからは「毎回同じ書き方で呼べるユーティリティ」にしておくとスッキリします。

import java.nio.charset.StandardCharsets;
import java.util.Base64;

public final class Base64s {

    private Base64s() {}

    public static String encodeToString(byte[] bytes) {
        return Base64.getEncoder().encodeToString(bytes);
    }

    public static String encodeUtf8(String text) {
        if (text == null) {
            return null;
        }
        byte[] bytes = text.getBytes(StandardCharsets.UTF_8);
        return encodeToString(bytes);
    }
}
Java

ここで深掘りしたい重要ポイントは二つあります。

一つ目は、「Base64 は本来“バイト列”を扱うものなので、文字列をエンコードしたいときは“まず文字列をバイト列にする”」という流れを意識することです。
encodeUtf8 では、UTF-8 でバイト列に変換してから Base64 にしています。

二つ目は、「文字コードを必ず明示する」ことです。
getBytes() を引数なしで呼ぶと、環境依存のデフォルトエンコーディングになってしまいます。
業務システムでは、基本的に StandardCharsets.UTF_8 を明示しておくのが安全です。


例題:文字列を Base64 にしてログや設定に埋め込む

シンプルなテキストのエンコード

まずは、単純な文字列を Base64 にしてみます。

public class Base64Example {

    public static void main(String[] args) {
        String original = "こんにちは、Base64!";
        String encoded  = Base64s.encodeUtf8(original);

        System.out.println("original = " + original);
        System.out.println("encoded  = " + encoded);
    }
}
Java

出力イメージは次のようになります。

original = こんにちは、Base64!
encoded  = 44GT44KT44Gr44Gh44Gv44CBQmFzZTY077yB

ここでのポイントは、「人間には意味不明な文字列に見えるが、これは“元の文字列を安全に運ぶための表現”に過ぎない」という感覚です。
設定ファイルや環境変数にこの Base64 文字列を書いておき、
アプリ起動時に逆変換して使う、というパターンもよくあります(復号ではなく“復元”というイメージです)。


例題:バイナリファイル(画像など)を Base64 にする

ファイル → バイト配列 → Base64 文字列

業務でよくあるのが、「画像ファイルを Base64 にして JSON に載せたい」というケースです。
例えば、PNG ファイルを読み込んで Base64 にするコードはこうなります。

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;

public final class FileBase64 {

    private FileBase64() {}

    public static String encodeFile(Path path) throws IOException {
        byte[] bytes = Files.readAllBytes(path);
        return Base64s.encodeToString(bytes);
    }
}
Java

使い方はこうです。

Path imagePath = Path.of("logo.png");
String base64 = FileBase64.encodeFile(imagePath);

System.out.println(base64.substring(0, 80) + "...");
Java

ここで深掘りしたいのは、「Base64 は“バイナリを文字列にする”のであって、“画像専用”でも“テキスト専用”でもない」ということです。
ファイルの種類に関係なく、byte[] にさえできれば、同じ encodeToString で Base64 にできます。

また、JSON に載せるときは、MIME タイプと組み合わせて Data URL 風にすることもあります。

{
  "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA..."
}

このように、「バイナリをテキストの世界に持ち込む橋渡し」として Base64 を使うイメージを持っておくと、使いどころが見えてきます。


URL や HTTP ヘッダで使う「URLセーフ Base64」

+ や / を避けたい場面

通常の Base64 では、+/ が文字として使われます。
しかし、URL のパスやクエリパラメータ、Cookie などにそのまま載せると、意味を持つ記号とぶつかって扱いづらくなります。

そのため、「URLセーフ Base64」というバリアントが用意されています。
Java では Base64.getUrlEncoder() を使います。

import java.util.Base64;

public final class Base64s {

    private Base64s() {}

    public static String encodeUrlSafe(byte[] bytes) {
        return Base64.getUrlEncoder().withoutPadding().encodeToString(bytes);
    }
}
Java

ここでの重要ポイントは、「URLセーフでは +- に、/_ に置き換わり、= のパディングを省略することが多い」ということです。
withoutPadding() を付けるかどうかは仕様次第ですが、トークンや ID などでよく使われるパターンです。

例えば、トークン生成でこう使えます。

import java.security.SecureRandom;

public final class TokenGenerator {

    private static final SecureRandom RANDOM = new SecureRandom();

    private TokenGenerator() {}

    public static String randomToken(int bytesLength) {
        byte[] bytes = new byte[bytesLength];
        RANDOM.nextBytes(bytes);
        return Base64s.encodeUrlSafe(bytes);
    }
}
Java

これで、「URL にそのまま載せても壊れにくいランダムトークン」を簡単に作れます。


Base64エンコードで意識したい設計のポイント

「エンコードの入口」を一箇所に決める

Base64 自体は単純ですが、プロジェクトのあちこちでバラバラに使い始めると、
「こっちは標準 Base64、あっちは URL セーフ」「こっちは UTF-8、あっちはデフォルトエンコーディング」といった揺れが出ます。

それを防ぐために、今回のような Base64s ユーティリティを「エンコードの入口」として決めておくと、
どこからでも同じルールで Base64 を扱えるようになります。

例えば、次のように役割を分けておくと分かりやすいです。

文字列 → Base64(UTF-8 固定)
バイト列 → Base64(標準)
バイト列 → Base64(URLセーフ)

呼び出し側は「どの用途か」だけを意識し、細かい設定はユーティリティに任せる、という形にするとスッキリします。

「エンコード=安全化」ではないことを理解する

Base64 は「見た目が変わる」ので、なんとなく「安全になった気」がしてしまいますが、
暗号化ではないので、誰でも簡単に元に戻せます。

つまり、「パスワードを Base64 にして DB に保存しているから安全」といった考え方は完全に誤りです。
Base64 はあくまで「運びやすくするための変換」であり、「秘匿するための仕組み」ではありません。

業務で使うときは、「どこまでが Base64 の役割で、どこからが暗号化やマスキングの役割か」を切り分けて考えることが大事です。


まとめ:Base64エンコードユーティリティで身につけたい感覚

Base64エンコードは、「バイナリを文字列に変える」という、とてもシンプルだけれど実務で頻出の技です。

押さえておきたい感覚は、まず「Base64 はバイト列を扱うので、文字列は必ず“文字コードを決めてバイト列にしてから”エンコードする」こと。
次に、「標準 Base64 と URLセーフ Base64 を使い分け、プロジェクトとしての入口(ユーティリティ)を一箇所に決める」こと。
そして、「Base64 は“運びやすくする変換”であって、“守るための仕組み”ではない」という線引きをはっきり理解しておくことです。

タイトルとURLをコピーしました