ทำไม escape_javascript ก่อนแสดงผลบางส่วน


120

ฉันกำลังดูตอน Railscast นี้และสงสัยว่าทำไมต้องโทรไปescape_javascriptที่นี่:

$("#reviews").append("<%= escape_javascript(render(:partial => @review)) %>");

อะไรคือสิ่งที่escape_javascriptใช้?

ตามเอกสาร Rails :

escape_javascript (จาวาสคริปต์)

Escape carrier return และอัญประกาศเดี่ยวและคู่สำหรับกลุ่ม JavaScript

แต่นั่นไม่ได้มีความหมายกับฉันมากนัก


23
FYI คำตอบที่ได้รับการยอมรับที่นี่ไม่ใช่คำตอบที่ถูกต้อง Kikito คือ
Steve

คำตอบ:


-3

เพราะคุณไม่ต้องการให้ผู้ใช้โพสต์ JavaScript ที่เบราว์เซอร์รันจริงหรือ?


4
แต่เวลาที่คุณต้องการส่งผ่านและแสดงรหัสจาวาสคริปต์ล่ะ?
berto77

ใช่จริงๆแล้วมันเป็นวิธีการจัดรูปแบบมากกว่า ไม่ได้ป้องกันไม่ให้ผู้ใช้เรียกใช้จาวาสคริปต์ของตนเอง ไม่มีสิ่งใดสามารถป้องกันได้
LasagnaAndroid

3
สิ่งนี้ไม่เป็นประโยชน์ ดูคำตอบของ kikitoแทน
nitsas

363

ง่ายกว่าที่จะเข้าใจหากคุณแบ่งรหัสออกเป็นสองส่วน

ส่วนแรก$("#reviews").append("<%= ... %>");คือ javascript กับ erb ซึ่งหมายความว่า<%= ... %>จะถูกแทนที่ด้วยรหัสทับทิมที่อยู่ข้างในจะส่งกลับ ผลลัพธ์ของการแทนที่นั้นต้องเป็น javascript ที่ถูกต้องมิฉะนั้นจะทำให้เกิดข้อผิดพลาดเมื่อไคลเอ็นต์พยายามประมวลผล ดังนั้นนั่นคือสิ่งแรกที่คุณต้องจาวาสคริปต์ที่ถูกต้อง

สิ่งที่ต้องคำนึงถึงอีกประการหนึ่งคือสิ่งที่ทับทิมสร้างขึ้นจะต้องอยู่ในสตริงจาวาสคริปต์ที่มีเครื่องหมายคำพูดคู่ - สังเกตเครื่องหมายคำพูดคู่รอบ ๆ<%= ... %>. ซึ่งหมายความว่าจาวาสคริปต์ที่สร้างขึ้นจะมีลักษณะดังนี้:

$("#reviews").append("...");

ตอนนี้เรามาตรวจสอบส่วนทับทิมภายในไฟล์<%= ... %>. อะไรrender(:partial => @review)ทำอย่างไร เป็นการแสดงผลบางส่วน - ซึ่งหมายความว่าสามารถแสดงรหัสประเภทใดก็ได้ - html, css ... หรือจาวาสคริปต์มากกว่า!

แล้วจะเกิดอะไรขึ้นถ้าบางส่วนของเรามี html ง่ายๆเช่นนี้?

<a href="/mycontroller/myaction">Action!</a> 

จำไว้ว่าจาวาสคริปต์ของคุณใช้สตริงที่ยกมาสองครั้งเป็นพารามิเตอร์? หากเราเพียงแค่แทนที่<%= ... %>ด้วยรหัสของบางส่วนนั้นแสดงว่าเรามีปัญหา - ทันทีที่href=มีเครื่องหมายคำพูดคู่! จาวาสคริปต์จะไม่ถูกต้อง:

// Without escaping, you get a broken javascript string at href
$("#reviews").append("<a href="/mycontroller/myaction">Action!</a>");

เพื่อไม่ให้สิ่งนี้เกิดขึ้นคุณต้องหลีกเลี่ยงอักขระพิเศษเหล่านี้เพื่อไม่ให้สตริงของคุณถูกตัด - คุณต้องมีสิ่งที่สร้างสิ่งนี้แทน:

<a href=\"/mycontroller/myaction\">Action!</a>

นี้สิ่งที่escape_javascriptไม่ ตรวจสอบให้แน่ใจว่าสตริงที่ส่งคืนจะไม่ "ทำลาย" จาวาสคริปต์ หากคุณใช้งานคุณจะได้ผลลัพธ์ที่ต้องการ:

$("#reviews").append("<a href=\"/mycontroller/myaction\">Action!</a>")

ความนับถือ!


4
ขอบคุณจริงๆคำอธิบายที่ดีมาก ฉันเดาว่าการใช้ 'escape_javascript' เป็นการทำให้เข้าใจผิดเพราะเราไม่ได้ใช้มันเพื่อหลีกเลี่ยงจาวาสคริปต์จริง คุณสามารถใส่แท็กสคริปต์ในบางส่วนและเรียกใช้จาวาสคริปต์ที่คุณต้องการได้
Steve

13
@Steve เห็นด้วยชื่อที่ดีกว่าจะเป็นescape_for_javascriptเพราะบ่อยครั้งที่คุณหนีรหัสอื่น ๆ (ตัวอย่างเช่น html) เพื่อที่จะไม่ทำลายจาวาสคริปต์
kikito

14
escape_javascript()ตอนนี้มีวิธีที่สั้นกว่า: ง่ายj()(ใน Rails 4 เป็นอย่างน้อย)
mjnissim

@kikito ใช้เอฟเฟกต์นี้ฉันพยายามสร้าง html บางส่วนที่ประกอบด้วยฟอร์มระยะไกลหรือไม่ ฉันกำลังพยายามค้นหาว่าเหตุใดการแสดงผลบางส่วนด้วยจาวาสคริปต์ที่มีรูปแบบอื่นที่จะส่งผ่านจาวาสคริปต์ทำให้คำขอที่สองเป็น html แทนที่จะเป็น js หากคุณมีเวลาโปรดดูคำถามที่ฉันโพสต์เกี่ยวกับเรื่องนี้ได้ไหม ขอบคุณ! คำถามของฉัน
Jake Smith

1
@JakeSmith ตอบในคำถามของคุณ
kikito

8

ผู้ใช้อาจโพสต์โค้ดที่เป็นอันตราย (ผู้ใช้ที่เป็นอันตราย) ซึ่งหากปล่อยไว้โดยไม่ใช้ Escape อาจถูกเรียกใช้งานซึ่งทำให้ผู้ใช้สามารถควบคุมแอปพลิเคชันของคุณได้

ลองสิ่งนี้:

<% variable = '"); alert("hi there' %>
$("#reviews").append("<%= variable %>");

ไม่ค่อยคุ้นเคยกับไวยากรณ์ของราง แต่ถ้าคุณไม่หนีvariableกล่องการแจ้งเตือนจะปรากฏขึ้นและฉันไม่คิดว่านั่นเป็นพฤติกรรมที่ตั้งใจไว้


8

ถ้าคุณดูที่มาที่นี่จะชัดเจนกว่ามาก

ฟังก์ชันนี้ทำงานได้สองสิ่งต่อไปนี้:

  1. แทนอักขระในสตริงอินพุตด้วยอักขระที่กำหนดในJS_ESCAPE_MAP

    จุดประสงค์ของสิ่งนี้คือเพื่อให้แน่ใจว่าโค้ดจาวาสคริปต์ได้รับการต่ออนุกรมอย่างถูกต้องโดยไม่รบกวนสตริงด้านนอกที่ฝังอยู่ ตัวอย่างเช่นหากคุณมีสตริงจาวาสคริปต์ในเครื่องหมายคำพูดคู่คำพูดทั้งหมดภายในสำหรับตัวอักษรสตริงจะต้องอยู่ในเครื่องหมายคำพูดเดียวเพื่อหลีกเลี่ยงไม่ให้โค้ดแตก

  2. ฟังก์ชั่นนี้ยังตรวจสอบว่าสตริงผลลัพธ์นั้นปลอดภัยหรือไม่ หากไม่เป็นเช่นนั้นก็จะทำการ Escape ที่จำเป็นเพื่อให้แน่ใจว่าสตริงกลายเป็น html ที่ปลอดภัยและส่งคืนผลลัพธ์

เมื่อคุณใช้ escape_javascript โดยปกติจะถูกฝังไว้ในสตริงอื่นหรือ html ที่มีอยู่แบบไดนามิก คุณต้องแน่ใจว่าการทำเช่นนี้จะไม่ทำให้ทั้งหน้าของคุณไม่แสดงผล

บางแง่มุมของการตอบกลับนี้ถูกชี้ให้เห็นในคำตอบอื่น ๆ แต่ฉันต้องการนำรายการทั้งหมดมารวมกันรวมถึงความแตกต่างระหว่างการหลีกเลี่ยงจาวาสคริปต์และการหลบหนี html นอกจากนี้บางคำตอบยังกล่าวพาดพิงว่าฟังก์ชันนี้ช่วยหลีกเลี่ยงการแทรกสคริปต์ ฉันไม่คิดว่านั่นคือจุดประสงค์ของฟังก์ชันนี้ ตัวอย่างเช่นในบทวิจารณ์ของคุณหากบทวิจารณ์ของคุณมีการแจ้งเตือน ('สวัสดี') เพียงต่อท้ายโหนดจะไม่ทำให้ป๊อปอัปเริ่มทำงาน คุณไม่ได้ฝังไว้ในฟังก์ชันที่เรียกใช้เมื่อโหลดหน้าเว็บหรือผ่านเหตุการณ์อื่น ๆ เพียงแค่มีการแจ้งเตือน ('hi there') เป็นส่วนหนึ่งของ html ของคุณไม่ได้หมายความว่าจะเรียกใช้งานเป็นจาวาสคริปต์

ที่กล่าวว่าฉันไม่ได้ปฏิเสธว่าการฉีดสคริปต์เป็นไปไม่ได้ แต่เพื่อหลีกเลี่ยงไม่ให้คุณต้องดำเนินการเมื่อคุณนำข้อมูลผู้ใช้และจัดเก็บไว้ในฐานข้อมูลของคุณ ฟังก์ชันและตัวอย่างที่คุณระบุเกี่ยวข้องกับการแสดงผลข้อมูลซึ่งได้บันทึกไว้แล้ว

ฉันหวังว่านี่จะช่วยและตอบคำถามของคุณได้

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