การส่งสตริงที่เข้ารหัส base64 ใน URL


243

จะปลอดภัยไหมที่จะส่งสตริงเบสที่เข้ารหัสแบบ raw64 ผ่านพารามิเตอร์ GET?



4
ไม่ใช่ไม่ใช่ - คำถามที่เชื่อมโยงนั้นใหม่กว่า ดังนั้นมันจึงทำให้คำถามที่ถูกเชื่อมโยงนั้นซ้ำกับคำถามนี้ ...
serge

คำตอบ:


206

ไม่คุณจะต้องเข้ารหัส url เนื่องจากสตริง base64 สามารถมีอักขระ "+", "=" และ "/" ซึ่งสามารถเปลี่ยนความหมายของข้อมูลของคุณ - ดูเหมือนโฟลเดอร์ย่อย

base64 อักขระที่ถูกต้องอยู่ด้านล่าง

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=

4
การเข้ารหัส URL เป็นการสิ้นเปลืองพื้นที่โดยเฉพาะอย่างยิ่งเมื่อ base64 นั้นปล่อยให้ตัวอักษรจำนวนมากไม่ได้ใช้
MichałGórny

21
ฉันไม่แน่ใจว่าฉันเข้าใจสิ่งที่คุณพูด - การเข้ารหัส URL จะไม่เปลี่ยนแปลงอักขระใด ๆ ยกเว้นอักขระสามตัวสุดท้ายในรายการด้านบนและเพื่อป้องกันไม่ให้ถูกตีความอย่างไม่ถูกต้องเนื่องจากมีความหมายอื่นใน URL เช่นเดียวกับ base64 ข้อมูลดั้งเดิมอาจเป็นแบบไบนารี่หรืออะไรก็ได้ แต่มันถูกเข้ารหัสในรูปแบบที่สามารถส่งได้อย่างง่ายดายโดยใช้โปรโตคอลอย่างง่าย
Thiyagaraj

3
ประการแรกคุณควรหลีกเลี่ยง '+' ด้วยเพราะอาจถูกแปลงเป็นอวกาศ ประการที่สองมีอักขระอย่างน้อยสองสามตัวที่ปลอดภัยสำหรับใช้ใน URL และไม่ได้ใช้ในชุดอักขระ 'มาตรฐาน' วิธีการของคุณสามารถเพิ่มขนาดของข้อมูลที่ถ่ายโอนได้สามครั้งในบางสถานการณ์ ในขณะที่การแทนที่ตัวละครเหล่านั้นด้วยคนอื่นจะทำเคล็ดลับในขณะที่รักษาความยาวเดียวกัน และมันก็เป็นโซลูชันมาตรฐานเช่นกัน
MichałGórny

8
en.wikipedia.org/wiki/Base64#URL_applications - กล่าวอย่างชัดเจนว่าการหลบหลีก 'ทำให้สตริงยาวขึ้นโดยไม่จำเป็น' และกล่าวถึงตัวแปรชุดอักขระสำรอง
MichałGórny

1
เนื่องจากคำตอบนี้ฉันจึงวินิจฉัยว่าเป็นสิ่งที่กล่าวถึง อักขระฐาน 64 ตัว (+, /, =) บางส่วนถูกเปลี่ยนแปลงเนื่องจากการประมวลผล URL เมื่อฉัน URL เข้ารหัสสตริงฐาน 64 ปัญหาได้รับการแก้ไข
Chuck Krutsinger

272

มีคุณสมบัติเพิ่มเติม base64 (ดูตารางที่นี่สำหรับข้อมูลเฉพาะ) แต่โดยพื้นฐานแล้วคุณต้องการ 65 ตัวอักษรเพื่อเข้ารหัส: 26 ตัวพิมพ์เล็ก + 26 ตัวพิมพ์ใหญ่ + 10 หลัก = 62

คุณต้องการอีกสอง [+ +, '/'] และ padding char '=' แต่ไม่มีของพวกเขาที่เป็นมิตรกับ url ดังนั้นเพียงใช้ตัวอักษรที่แตกต่างกันสำหรับพวกเขาและคุณตั้ง มาตรฐานจากแผนภูมิด้านบนคือ ['-', '_'] แต่คุณสามารถใช้ตัวอักษรอื่นได้ตราบใดที่คุณถอดรหัสพวกมันเหมือนกันและไม่จำเป็นต้องแบ่งปันกับคนอื่น

ฉันขอแนะนำเพียงแค่เขียนผู้ช่วยของคุณเอง เช่นนี้จากความคิดเห็นในหน้าคู่มือ php สำหรับ base64_encode :

function base64_url_encode($input) {
 return strtr(base64_encode($input), '+/=', '._-');
}

function base64_url_decode($input) {
 return base64_decode(strtr($input, '._-', '+/='));
}

53
ทางออกที่ดียกเว้นคอมม่าไม่ได้ถูกสงวนไว้ใน URL ฉันแนะนำให้ใช้ '~' (tilde) หรือ '.' (จุด) แทน
kralyk

11
@kralyk: ฉันขอแนะนำเพียงแค่ใช้urlencodeตามคำแนะนำของคำตอบของ rodrigo-silveira การสร้างฟังก์ชั่นใหม่สองฟังก์ชั่นเพื่อประหยัด chars สองสามตัวในความยาว url เหมือนเข้ามาในบ้านของคุณผ่านหน้าต่างแทนที่จะใช้เพียงประตู
Marco Demaio

5
@MarcoDemaio โดยไม่รู้ว่ามันจะถูกใช้อย่างไรมันเป็นไปไม่ได้ที่จะบอกว่ามันเป็นเพียงตัวละครไม่กี่ตัว อักขระที่เข้ารหัสทุกตัวจะมีความยาวสามเท่าและทำไมจะไม่ "+++ ... " เป็นสตริงเบส 64 ที่ถูกต้อง URL มีขีด จำกัด ของเบราว์เซอร์และการเพิ่ม URL อาจทำให้คุณถึงขีด จำกัด เหล่านั้น
leewz

10
@RandalSchwartz ตัวหนอนมี URL ที่ปลอดภัย จาก RFC3986:unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
kralyk

3
เนื่องจาก,ควร urlencoded เป็น%2Cฉันขอแนะนำให้ใช้._- แทนที่จะ-_,เป็นตัวแปรตัวเดียวในen.wikipedia.org/wiki/Base64#Variants_summary_tableที่คอยตามมา =
PaulH

75

@ joeshmo หรือแทนที่จะเขียนฟังก์ชั่นตัวช่วยคุณสามารถ urlencode สตริงที่เข้ารหัส base64 สิ่งนี้จะทำสิ่งเดียวกันกับฟังก์ชั่นตัวช่วยของคุณ แต่ไม่จำเป็นต้องใช้ฟังก์ชั่นพิเศษอีกสองอย่าง

$str = 'Some String';

$encoded = urlencode( base64_encode( $str ) );
$decoded = base64_decode( urldecode( $encoded ) );

2
ผลลัพธ์ไม่เหมือนกันทุกประการ urlencode ใช้ 3 ตัวอักษรเพื่อเข้ารหัสอักขระที่ไม่ถูกต้องและโซลูชันของ joeshmo ใช้ 1 มันไม่ได้แตกต่างกันมาก แต่ก็ยังเสีย
Josef Borkovec

1
@JosefBorkovec จริงเหรอ? แล้วนี่ก็หมายความว่าจำนวนไบต์พื้นฐานเท่ากัน 64-> url-> ที่ถูกเข้ารหัสอาจมีความยาวต่างกันได้หลายแบบในขณะที่วิธีแก้ปัญหาอื่นให้ความยาวที่คาดเดาได้ใช่ไหม
มนุษยชาติ

@humanityANDpeace ใช่ urlencode เป็นคำตอบที่น่าเบื่อเพราะมันเพิ่มขนาดของสตริง base64 ให้สามเท่า คุณไม่สามารถใช้บัฟเฟอร์ซ้ำได้เนื่องจากเอาต์พุตมีขนาดใหญ่กว่าอินพุต
Navin

4
การขยายจาก 1 ถึง 3 ตัวอักษรเกิดขึ้นที่ 3 จาก 64 ตัวอักษรโดยเฉลี่ยดังนั้นจึงเป็นค่าใช้จ่าย 9% (2 *
3/64

ระวัง/ตัวละครถ้าคุณผ่านมันไม่ได้เป็นพารามิเตอร์ GET แต่เป็นเส้นทางใน URL มันจะเปลี่ยนเส้นทางของคุณหากคุณไม่ได้แทนที่/ด้วยอย่างอื่นทั้งสองด้าน
NeverEndingQueue

41

บันทึกย่อเบื้องต้นฉันมีแนวโน้มที่จะโพสต์คำอธิบายเล็ก ๆ น้อย ๆ เนื่องจากคำตอบบางส่วนของที่นี่เป็นการหลอกลวงเล็กน้อย (หากไม่ถูกต้อง)

คำตอบคือไม่คุณไม่สามารถส่งพารามิเตอร์ base64 ที่เข้ารหัสได้ภายในสตริงการสืบค้น URL เนื่องจากเครื่องหมายบวกจะถูกแปลงเป็น SPACE ภายในอาร์เรย์ส่วนกลางของ $ _GET กล่าวอีกนัยหนึ่งถ้าคุณส่งtest.php? myVar = stringwith + sign to

//test.php
print $_GET['myVar'];

ผลลัพธ์จะเป็น:
stringwith sign

วิธีง่ายๆในการแก้ปัญหานี้ก็คือเพียงแค่urlencode()สตริง base64 ของคุณก่อนที่จะเพิ่มลงในสตริงเคียวรีเพื่อหลีกเลี่ยงรหัส +, = และ / ตัวอักษรไปยังรหัส% ## ตัวอย่างเช่นurlencode("stringwith+sign")ผลตอบแทนstringwith%2Bsign

เมื่อคุณประมวลผลแอ็คชัน PHP จะดูแลการถอดรหัสสตริงเคียวรีโดยอัตโนมัติเมื่อเติม $ _GET โกลบอล ตัวอย่างเช่นถ้าผมส่งtest.php? myvar = stringwith% 2Bsignไป

//test.php
print $_GET['myVar'];

ผลลัพธ์ที่ได้คือ:
stringwith+sign

คุณไม่ต้องการurldecode()สตริง $ _GET ที่ส่งคืนเนื่องจาก + จะถูกแปลงเป็นช่องว่าง
กล่าวอีกนัยหนึ่งถ้าฉันส่งtest.php? myVar = stringwith% 2Bsign เดียวกันให้

//test.php
$string = urldecode($_GET['myVar']);
print $string;

ผลลัพธ์ที่ได้คือสิ่งที่ไม่คาดคิด:
stringwith sign

มันจะปลอดภัยต่อrawurldecode()การป้อนข้อมูล แต่มันจะซ้ำซ้อนและดังนั้นจึงไม่จำเป็น


1
คำตอบที่ดี คุณสามารถใช้โค้ด PHP โดยไม่มีแท็กเริ่มต้นและแท็กสิ้นสุดในเว็บไซต์นี้หากคำถามถูกติดแท็กphp (ส่วนใหญ่มักจะชัดเจนจากบริบทของคำถาม) หากคุณเพิ่มช่องว่างสองช่องที่ท้ายบรรทัดคุณจะเห็นเครื่องหมาย<br>ดังนั้นไม่จำเป็นต้องพิมพ์ HTML มาก ฉันหวังว่านี่จะช่วยฉันแก้ไขคำตอบของคุณเล็กน้อยเพื่อปรับปรุงให้ดียิ่งขึ้น
hakre

ขอบคุณสำหรับการกล่าวถึงว่า PHP ถอดรหัส URL สำหรับคุณ ที่ช่วยฉันจากการตกอยู่ในโพรงกระต่าย
Cocest

คำตอบที่ดี -> คุณไม่ต้องการ urldecode () สตริง $ _GET ที่ส่งคืนเนื่องจาก + จะถูกแปลงเป็นช่องว่าง อย่างไรก็ตามจะปลอดภัยกับ rawurldecode () อินพุต แต่
MarcoZen

14

ใช่และไม่.

ชุดอักขระพื้นฐานของ base64 ในบางกรณีอาจขัดแย้งกับแบบแผนดั้งเดิมที่ใช้ใน URL แต่การใช้งาน base64 จำนวนมากทำให้คุณสามารถเปลี่ยนชุดอักขระเพื่อให้ตรงกับ URL ที่ดีขึ้นหรือแม้กระทั่งมาพร้อมกับหนึ่ง (เช่น Python urlsafe_b64encode())

ปัญหาอื่นที่คุณอาจประสบคือขีดจำกัดความยาวของ URL หรือมากกว่า - ไม่มีข้อ จำกัด ดังกล่าว เนื่องจากมาตรฐานไม่ได้ระบุความยาวสูงสุดเบราว์เซอร์เซิร์ฟเวอร์ไลบรารีและซอฟต์แวร์อื่น ๆ ที่ทำงานกับโปรโตคอล HTTP อาจกำหนดขีด จำกัด ของตัวเอง คุณอาจดูที่บทความนี้: คำถามที่พบบ่อย WWW: ความยาวสูงสุดของ URL คืออะไร?


8

มันเป็น base64url encode ที่คุณสามารถลองใช้ได้เพียงแค่ขยายโค้ดของ joeshmo ด้านบน

function base64url_encode($data) {
return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function base64url_decode($data) {
return base64_decode(str_pad(strtr($data, '-_', '+/'), strlen($data) % 4, '=', STR_PAD_RIGHT));
}

ใช้งานได้กับข้อมูลที่เข้ารหัสด้วย Java'sBase64.getUrlEncoder().withoutPadding().encodeToString()

4

ฉันไม่คิดว่าจะปลอดภัยเพราะเช่นตัวอักษร "=" ใช้ในฐาน 64 และยังใช้ในการแยกความแตกต่างของพารามิเตอร์จากค่าใน HTTP GET


1

ในทางทฤษฎีใช่ตราบใดที่คุณไม่เกินความยาวสูงสุดของสตริงข้อความค้นหา / url สำหรับไคลเอ็นต์หรือเซิร์ฟเวอร์

ในทางปฏิบัติสิ่งต่าง ๆ อาจมีความยุ่งยากเล็กน้อย ตัวอย่างเช่นมันสามารถทริกเกอร์ HttpRequestValidationException บน ASP.NET หากค่าเกิดขึ้นเพื่อให้มี "on" และคุณปล่อยไว้ในส่วนท้าย "=="


คุณไม่พูดถึงอักขระ +, / หรือ = ซึ่งทำให้ URL ไม่ถูกต้องในบางกรณี
Will Bickford

0

สำหรับการเข้ารหัส URL ที่ปลอดภัยเช่นเดียวกับbase64.urlsafe_b64encode(...)ใน Python รหัสด้านล่างใช้งานได้กับฉัน 100%

function base64UrlSafeEncode(string $input)
{
   return str_replace(['+', '/'], ['-', '_'], base64_encode($input));
}

-10

ใช่มันปลอดภัยเสมอ แน่นอน base64 ประกอบด้วย: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/= แต่เข้ารหัส base64 +สตริงมักจะไม่มี +จะถูกแปลงเป็นพื้นที่ว่างส่งผลให้เกิดการถอดรหัสสตริงที่ไม่ถูกต้อง /ปลอดภัยในคู่รับพารามิเตอร์ =อยู่เสมอที่ส่วนท้ายของสตริงที่เข้ารหัส base64 และฝั่งเซิร์ฟเวอร์สามารถแก้ไข=ได้โดยตรง


ฉันเดาว่านี่ถูกต้องเนื่องจากการทดลองที่ฉันทำกับการเข้ารหัส base64 (โดยไม่ต้องเข้ารหัส url) นั้นประสบความสำเร็จ แต่ฉันสงสัยว่ามีเอกสารใดบ้างที่คุณสามารถใช้สำรองข้อมูลได้
Sean the Bean

1
คุณพูดว่า "ปลอดภัยเสมอ" แต่จากนั้นคุณพูดว่า "มักจะไม่มี +" ดังนั้นคุณแย้งตัวเอง เครื่องหมาย + จะทำให้เกิดปัญหาหากคุณมีมันในสตริง base64 ของคุณ
Nick Humrich
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.