Co to jest kodowanie Base64? Jak działa i gdzie się go używa
Kodowanie Base64 to sposób zapisu dowolnych danych, tekstu, obrazu, dowolnych bajtów, za pomocą tylko 64 drukowalnych znaków ASCII, żeby dane bezpiecznie przeszły przez systemy obsługujące wyłącznie tekst. Alfabet Base64 to litery A-Z, a-z, cyfry 0-9, plus znaki + i /, razem 64 symbole, do których dochodzi jeszcze = jako znak dopełnienia. Każde 3 bajty danych wejściowych zamieniają się w dokładnie 4 znaki Base64, więc wynik jest zawsze około 33% większy od oryginału.
Czego Base64 nie robi
Zanim przejdziemy do mechaniki, jedna rzecz musi być jasna: Base64 to nie jest szyfrowanie ani kompresja. Nie ma tu żadnego klucza, nie ma tajemnicy, każdy może zdekodować ciąg Base64 z powrotem do oryginału w ułamku sekundy, a wynik jest większy od danych wejściowych, nie mniejszy. To najczęstsze nieporozumienie wokół Base64: ktoś “koduje” hasło albo token do Base64 i traktuje to jako ochronę danych. Nie jest. Base64 zmienia tylko format zapisu, nie ukrywa treści przed nikim, kto wie, że to Base64, a rozpoznać to po samym wyglądzie ciągu jest banalnie łatwo. Jeśli potrzebujesz poufności, potrzebujesz prawdziwego szyfrowania, nie kodowania.
Jak to działa: kodowanie “Man” bit po bicie
Base64 nie jest żadną magią, to konwersja podstawy z 8-bitowych bajtów na 6-bitowe porcje. Weźmy tekst “Man” i przejdźmy cały proces krok po kroku.
Najpierw każdy znak zamienia się na swoją wartość ASCII, a potem na 8-bitowy zapis binarny:
| Znak | Wartość ASCII | Zapis binarny (8 bitów) |
|---|---|---|
| M | 77 | 01001101 |
| a | 97 | 01100001 |
| n | 110 | 01101110 |
Sklejone razem te trzy bajty dają 24 bity: 010011010110000101101110.
Base64 nie czyta tych bitów po 8, tylko po 6, bo 6 bitów daje dokładnie 64 możliwe kombinacje, czyli tyle, ile ma znaków alfabet Base64. Dzielimy więc 24 bity na cztery grupy po 6:
010011 | 010110 | 000101 | 101110
Każdą grupę zamieniamy na liczbę dziesiętną, a tę liczbę na znak z alfabetu Base64:
| Grupa 6-bitowa | Wartość dziesiętna | Znak Base64 |
|---|---|---|
| 010011 | 19 | T |
| 010110 | 22 | W |
| 000101 | 5 | F |
| 101110 | 46 | u |
Wynik: Man staje się TWFu. Trzy bajty zamieniły się w cztery znaki, dokładnie jak mówi zasada 3 bajty na 4 znaki. Żadnej magii, tylko inny sposób grupowania tych samych bitów.
Dopełnienie: dlaczego niektóre ciągi Base64 kończą się na =
Algorytm działa czysto tylko wtedy, gdy dane wejściowe da się podzielić na kompletne trójki bajtów. Kiedy zostaje 1 albo 2 bajty na końcu, Base64 dopełnia brakujące miejsce znakiem =, żeby długość wyniku zawsze była wielokrotnością 4.
| Tekst wejściowy | Bajtów | Wynik Base64 | Co się dzieje |
|---|---|---|---|
| M | 1 | TQ== | 2 znaki realnych danych + 2 znaki dopełnienia |
| Ma | 2 | TWE= | 3 znaki realnych danych + 1 znak dopełnienia |
| Man | 3 | TWFu | 4 znaki, bez dopełnienia |
Jeden bajt nie wypełnia całej trójki, więc dekoder dostaje tylko część informacji potrzebnej do złożenia pełnych 6-bitowych grup, stąd dwa = przy TQ==. Dwa bajty wypełniają trójkę częściowo, stąd jeden = przy TWE=. Trzy bajty to pełna trójka, więc TWFu nie potrzebuje żadnego dopełnienia. To właśnie te znaki = na końcu długiego ciągu Base64 zdradzają, ile bajtów zostało “nadmiarowych” w ostatniej grupie.
Gdzie naprawdę spotkasz Base64
Base64 nie jest ciekawostką akademicką, pojawia się w wielu miejscach, z którymi programiści stykają się codziennie:
| Przykład wejściowy | Kontekst użycia | Wynik Base64 |
|---|---|---|
Hello, World! | zwykły tekst | SGVsbG8sIFdvcmxkIQ== |
user:pass1234 | nagłówek HTTP Basic Auth | dXNlcjpwYXNzMTIzNA== |
{"id":42,"active":true} | mały payload JSON w URL-u albo w segmencie JWT | eyJpZCI6NDIsImFjdGl2ZSI6dHJ1ZX0= |
café | tekst z akcentem, UTF-8 | Y2Fmw6k= |
🚀 | emoji, UTF-8 | 8J+agA== |
Nagłówek Authorization: Basic <base64(login:hasło)> w HTTP Basic Authentication to dosłownie ten mechanizm w akcji: przeglądarka albo klient API zamienia user:pass1234 na dXNlcjpwYXNzMTIzNA== i wysyła to jako nagłówek. Podobnie działa osadzanie małego pliku, na przykład ikony, bezpośrednio w kodzie CSS albo HTML jako data: URL, zamiast trzymać go w osobnym pliku. Załączniki e-mail w formacie MIME również lecą jako Base64, bo protokół pocztowy z lat 80. potrafi bezpiecznie przenosić tylko tekst.
Tokeny JWT (JSON Web Token) to trzy segmenty Base64url oddzielone kropkami: header.payload.signature. Środkowy segment, payload, to zwykły JSON zakodowany w Base64, więc wystarczy wkleić go do dekodera Base64, żeby zobaczyć, jakie dane niesie token, na przykład ID użytkownika czy datę wygaśnięcia. Podpis (trzeci segment) to co innego, kryptograficzna sygnatura, ale sam payload odczytasz zwykłym dekoderem Base64, tym samym, którego użyjesz niżej na tej stronie.
Warto zwrócić uwagę na café i 🚀: to przykłady tego, że Base64 koduje bajty, nie znaki. é w UTF-8 zajmuje 2 bajty, więc czteroliterowe słowo café (a, é liczy się jako jeden znak, ale dwa bajty) daje w sumie 5 bajtów wejściowych i 8 znaków Base64 na wyjściu, więcej niż intuicyjnie sugerowałoby liczenie po znakach. Emoji 🚀 to w UTF-8 aż 4 bajty, mimo że wizualnie to jeden “znak”, i te 4 bajty kodują się tak samo jak każde inne dane binarne.
Zakoduj lub zdekoduj własny tekst
Wpisz dowolny tekst poniżej, żeby zobaczyć jego zapis w Base64, albo wklej gotowy ciąg Base64, żeby odczytać, co się pod nim kryje.
Częste błędy i przypadki szczególne
Traktowanie Base64 jako zabezpieczenia. To nie technikalia, to realny błąd bezpieczeństwa. Base64 nie ma klucza, nie ma sekretu, każdy z dostępem do zakodowanego ciągu może go zdekodować w jednej linijce kodu. Jeśli w logach albo w bazie danych widzisz hasło “zakodowane w Base64”, to hasło jest w praktyce jawne.
Standardowy Base64 nie jest bezpieczny dla adresów URL. Znaki +, / i = mają specjalne znaczenie w URL-ach i nazwach plików, więc surowy Base64 wklejony do parametru zapytania może zostać uszkodzony albo źle zinterpretowany. Dlatego istnieje odmiana Base64url, która zamienia + na - i / na _, a często w ogóle pomija dopełnienie =. Jeśli widzisz w URL-u ciąg przypominający Base64, ale bez +, / czy =, to najpewniej właśnie ta odmiana, dokładnie ta, której używają segmenty tokenów JWT.
Białe znaki i brakujące dopełnienie psują dekodowanie. Niektóre dekodery, zwłaszcza te napisane rygorystycznie, odrzucą ciąg Base64 ze spacją, złamaniem linii w środku albo z brakującym = na końcu. Jeśli kopiujesz ciąg Base64 z e-maila albo z pliku tekstowego, sprawdź, czy przypadkiem nie wkradł się tam znak nowej linii.
Wielobajtowy tekst UTF-8 zaskakuje długością wyniku. Akcenty, znaki CJK (chińskie, japońskie, koreańskie) czy emoji zajmują więcej niż 1 bajt na znak, więc liczba widocznych znaków wcale nie odpowiada liczbie bajtów wejściowych, a to właśnie liczba bajtów decyduje o długości wyniku Base64. Przykłady café i 🚀 wyżej pokazują to dokładnie.
Podwójne kodowanie przez pomyłkę. Zakodowanie już zakodowanego ciągu Base64 jeszcze raz jest łatwym błędem, zwłaszcza w skryptach, które łączą wiele kroków. Efekt: jedno dekodowanie zwraca nie oryginalny tekst, tylko kolejny ciąg Base64, który wygląda jak bezsensowny bełkot, dopóki nie zdekodujesz go po raz drugi.
Najczęściej zadawane pytania
Czym różni się kodowanie od szyfrowania? Kodowanie, takie jak Base64, to tylko zmiana formatu zapisu danych, odwracalna przez każdego bez żadnego sekretu. Szyfrowanie wymaga klucza i ma za zadanie ukryć treść przed osobami bez tego klucza. Base64 nie chroni niczego, jedynie zapisuje dane w formacie bezpiecznym dla systemów tekstowych.
Dlaczego wynik Base64 jest większy od oryginału? Bo każde 3 bajty danych wejściowych (24 bity) zamieniają się na 4 znaki Base64, a każdy znak reprezentuje tylko 6 bitów zamiast 8. Ten narzut daje w efekcie wynik około 33% większy niż dane źródłowe, niezależnie od tego, co koduje.
Czy Base64 obsługuje polskie znaki i emoji? Tak, bo Base64 działa na poziomie bajtów, nie znaków. Tekst jest najpierw zamieniany na bajty w UTF-8, a dopiero te bajty trafiają do algorytmu Base64, więc ą, ę, ż czy emoji kodują się bezproblemowo, tylko zajmują więcej bajtów niż zwykłe litery ASCII.
Co oznaczają znaki = na końcu ciągu Base64?
To dopełnienie, które pojawia się, gdy liczba bajtów wejściowych nie dzieli się równo przez 3. Jeden znak = oznacza, że ostatnia grupa miała 2 bajty zamiast 3, dwa znaki == oznaczają, że została tylko 1 bajt. Ciąg, który dzieli się idealnie na trójki, nie potrzebuje żadnego dopełnienia.
Czy mogę zdekodować token JWT w tym dekoderze? Środkowy segment tokenu JWT (payload, między dwiema kropkami) to zwykły JSON zakodowany w Base64url, więc dekoder poniżej odczyta go bez problemu. Podpis w trzecim segmencie to jednak dane kryptograficzne, nie zwykły tekst, więc jego zdekodowanie nie da czytelnej treści, to zresztą działa zgodnie z zamysłem: podpis ma potwierdzać integralność tokenu, nie nieść informacji.