2009-08-12 39 views
209

Có cách nào được khuyến nghị để thoát các ký tự <, >, "& khi xuất HTML trong mã Java thuần túy không? (Khác hơn là làm theo cách thủ công như sau, nghĩa là).Phương pháp được khuyến nghị để thoát HTML trong Java

String source = "The less than sign (<) and ampersand (&) must be escaped before using them in HTML"; 
String escaped = source.replace("<", "&lt;").replace("&", "&amp;"); // ... 
+1

Hãy lưu ý rằng nếu bạn đang cung cấp vào một thuộc tính HTML không thể viện chứng, rằng khác các ký tự như không gian, tab, backspace, v.v. có thể cho phép kẻ tấn công giới thiệu thuộc tính javascript mà không có bất kỳ ký tự nào được liệt kê. Xem Bảng chống gian lận XSS của OWASP để biết thêm. –

Trả lời

223

StringEscapeUtils từ Apache Commons Lang:

import static org.apache.commons.lang.StringEscapeUtils.escapeHtml; 
// ... 
String source = "The less than sign (<) and ampersand (&) must be escaped before using them in HTML"; 
String escaped = escapeHtml(source); 

Đối version 3:

import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4; 
// ... 
String escaped = escapeHtml4(source); 
+2

Trong khi 'StringEscapeUtils' là tốt đẹp, nó sẽ không thoát khỏi khoảng trắng đúng cho các thuộc tính nếu bạn muốn tránh bình thường hóa khoảng trắng HTML/XML. Xem câu trả lời của tôi để biết thêm chi tiết. –

+0

StringEscapeUtils.escapeHtml() chỉ chấp nhận Chuỗi là đầu vào, có vẻ như không cần thiết cứng nhắc. Trong thế giới hiện đại của JSON, một số thứ đầu ra cho trang sẽ là các con số, ví dụ, trong trường hợp này, phương thức này phá vỡ. – greim

+19

Ví dụ trên bị hỏng. Sử dụng phương thức escapeHtml4() ngay bây giờ. – stackoverflowuser2010

108

Một thay thế cho Apache Commons: HtmlUtils.htmlEscape(String input) phương pháp sử dụng Spring 's.

+8

Cảm ơn bạn. Tôi đã sử dụng nó (thay vì 'StringEscapeUtils.escapeHtml()' từ 'apache-commons' 2.6) vì nó để lại các ký tự tiếng Nga. –

+6

Điều đó rất hữu ích. TBH Tôi cung cấp cho Apache công cụ một bến rộng những ngày này. – Adamski

+1

Tôi cũng đã sử dụng nó, nó cũng để lại các ký tự Trung Quốc. – smartwjw

12

Đối với một số mục đích, HtmlUtils:

import org.springframework.web.util.HtmlUtils; 
[...] 
HtmlUtils.htmlEscapeDecimal("&")` //gives &#38; 
HtmlUtils.htmlEscape("&")` //gives &amp; 
45

Có một phiên bản mới hơn của Apache Commons Lang library và nó sử dụng tên gói khác (org.apache.commons.lang3). StringEscapeUtils hiện có các phương pháp tĩnh khác nhau để thoát các loại tài liệu khác nhau (http://commons.apache.org/proper/commons-lang/javadocs/api-3.0/index.html). Vì vậy, để thoát chuỗi HTML phiên bản 4.0:

import static org.apache.commons.lang3.StringEscapeUtils.escapeHtml4; 

String output = escapeHtml4("The less than sign (<) and ampersand (&) must be escaped before using them in HTML"); 
+1

Thật không may là không có gì tồn tại cho HTML 5, cũng không làm các tài liệu Apache xác định nếu nó là thích hợp để sử dụng escapeHtml4 cho HTML 5. –

32

Hãy cẩn thận với điều này. Có một số ngữ cảnh khác nhau trong một tài liệu HTML: Bên trong một phần tử, giá trị thuộc tính được trích dẫn, giá trị thuộc tính unquoted, thuộc tính URL, javascript, CSS, v.v ... Bạn sẽ cần sử dụng một phương thức mã hóa khác cho mỗi những điều này để ngăn chặn Script-Cross-Site (XSS). Kiểm tra Bảng gian lận ngăn chặn XSS của OWASP để biết chi tiết về từng ngữ cảnh này - https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet. Bạn có thể tìm các phương thức thoát cho mỗi ngữ cảnh trong thư viện OWASP ESAPI - https://github.com/ESAPI/esapi-java-legacy.

+5

CẢM ƠN BẠN chỉ ra rằng * bối cảnh * mà bạn muốn mã hóa đầu ra rất nhiều vấn đề. Thuật ngữ "mã hóa" cũng là một động từ thích hợp hơn nhiều so với "thoát", là tốt. Escape ngụ ý một số loại hack đặc biệt, trái ngược với "làm thế nào để tôi * mã hóa * chuỗi này cho: một thuộc tính XHTML/tham số truy vấn SQL/trường chuỗi PostScript/đầu ra CSV? – Roboprog

+2

'Mã hóa' và 'thoát' đều được sử dụng rộng rãi Thuật ngữ "thoát" thường được sử dụng khi quá trình thêm một "ký tự thoát" trước một ký tự liên quan đến cú pháp, chẳng hạn như thoát ký tự trích dẫn bằng dấu gạch chéo ngược \ "Thuật ngữ" mã hóa "thường được sử dụng hơn khi bạn dịch một ký tự sang một dạng khác, chẳng hạn như URL mã hóa ký tự trích dẫn% 22 hoặc mã hóa thực thể HTML là & # x22 hoặc @quot. –

+0

http://owasp-esapi-java.googlecode.com/svn/trunk_doc/latest/index.html. liên kết bây giờ đã phá vỡ –

35

trên Android (API 16 hoặc cao hơn), bạn có thể:

Html.escapeHtml(textToScape); 

hoặc cho API thấp:

TextUtils.htmlEncode(textToScape); 
+0

Có lý do nào để sử dụng 'escapeHtml' thay vì' htmlEncode' không? – Muz

+2

Xem thêm [câu hỏi của tôi] (http://stackoverflow.com/questions/35104032/whats-the-difference-between-androids-html-escapehtml-and-textutils-htmlencode) về sự khác biệt giữa hai câu hỏi này. (@Muz) – JonasCz

10

Trong khi @dfa câu trả lời của org.apache.commons.lang.StringEscapeUtils.escapeHtml là tốt đẹp và tôi đã sử dụng nó trong quá khứ không nên sử dụng nó để thoát HTML (hoặc XML) các thuộc tính nếu không khoảng trắng sẽ được chuẩn hóa (nghĩa là tất cả các ký tự trắng khoảng trắng liền kề sẽ trở thành một khoảng trắng).

Tôi biết điều này vì tôi đã có lỗi được gửi vào thư viện của tôi (JATL) cho các thuộc tính trong đó khoảng trắng không được giữ nguyên. Vì vậy, tôi có một giọt (copy n 'paste) class (of which I stole some from JDOM) that differentiates the escaping of attributes and element content.

Mặc dù điều này có thể không quan trọng nhiều trong quá khứ (thoát thuộc tính thích hợp) nhưng nó ngày càng trở nên quan tâm nhiều hơn đến việc sử dụng sử dụng thuộc tính data- của HTML5.

47

đẹp phương pháp ngắn:

public static String escapeHTML(String s) { 
    StringBuilder out = new StringBuilder(Math.max(16, s.length())); 
    for (int i = 0; i < s.length(); i++) { 
     char c = s.charAt(i); 
     if (c > 127 || c == '"' || c == '<' || c == '>' || c == '&') { 
      out.append("&#"); 
      out.append((int) c); 
      out.append(';'); 
     } else { 
      out.append(c); 
     } 
    } 
    return out.toString(); 
} 

Dựa trên https://stackoverflow.com/a/8838023/1199155 (amp là mất tích ở đó).Bốn ký tự kiểm tra trong mệnh đề if là những người duy nhất dưới 128, theo http://www.w3.org/TR/html4/sgml/entities.html

+0

Đẹp. Nó không sử dụng "phiên bản html" của các mã hóa (ví dụ: "á" sẽ là "& aacute;" thay vì "á"), nhưng vì các số làm việc ngay cả trong IE7 tôi đoán tôi không phải lo lắng . Cảm ơn. – nonzaprej

27

Đối với những người sử dụng Google Ổi:

import com.google.common.html.HtmlEscapers; 
[...] 
String source = "The less than sign (<) and ampersand (&) must be escaped before using them in HTML"; 
String escaped = HtmlEscapers.htmlEscaper().escape(source); 
Các vấn đề liên quan