Java'da HTML'den kaçmak için önerilen yöntem


262

Kaçmak için önerilen bir yolu var mı <, >, "ve &düz Java kodunda karakterler çıkış olarak HTML? (Aşağıdakileri manuel olarak yapmak dışında).

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

2
Alıntılanmamış bir HTML özniteliğine çıkış yapıyorsanız, boşluk, sekme, geri silme vb. Diğer karakterlerin saldırganların listelenen karakterlerden herhangi biri olmadan javascript öznitelikleri eklemesine izin verebileceğini unutmayın. Daha fazla bilgi için OWASP XSS Önleme Hile Sayfasına bakın.
Jeff Williams

BTW, bu kodda, düzgün çalışması için "&" işaretinden "&" önce kaçmalısınız ("& lt;" yerine "& amp;" ile değiştirilir, aksi takdirde "<lt" olarak işlenir, sonra "< "):source.replace("&", "&amp;").replace("<", "&lt;");
Tey '23

Yanıtlar:


261

StringEscapeUtils gelen 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);

İçin sürüm 3 :

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

2
Güzel olsa da StringEscapeUtils, HTML / XML boşluk normalizasyonundan kaçınmak istiyorsanız, özellikler için boşluktan düzgün bir şekilde kaçmayacaktır. Daha fazla ayrıntı için cevabıma bakın.
Adam Gent

21
Yukarıdaki örnek bozuldu. Şimdi escapeHtml4 () yöntemini kullanın.
stackoverflowuser2010

3
Guava hayranları için aşağıdaki okranz'ın cevabına bakınız.
George Hawkins

2
Web sayfasında UTF-8 kodlaması varsa, tek ihtiyacımız olan Guava'nın sadece aşağıdaki beş ASCII karakterinden kaçan htmlEscaper'ı vardır: '"& <>. sayfaları?
zdenekca

4
Artık commons-lang3'te kullanımdan kaldırılmıştır. Commons.apache.org/proper/commons-text
Danny

137

Kullanım: Apache Commons bir alternatif Yay 'in HtmlUtils.htmlEscape(String input)yöntemi.


9
Teşekkürler. Ben (yerine kullandım StringEscapeUtils.escapeHtml()den apache-commonsolduğu gibi Rus karakterleri bıraktığı için 2,6).
Slava Semushin

6
Bunu bilmek güzel. TBH Bugünlerde Apache'ye geniş bir yatak veriyorum.
Adamski

1
Ben de kullandım, Çince karakterleri olduğu gibi bırakıyor.
smartwjw

Aşağıda belirtilen guava alternatifiyle nasıl karşılaştırılır?
vishvAs vAsuki

2
Ayrıca kesme işaretini de kodlar, bu yüzden apache'nin aksine aslında yararlıdır StringEscapeUtils
David Balažic

57

Güzel kısa yöntem:

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 == '>' || c == '&') {
            out.append("&#");
            out.append((int) c);
            out.append(';');
        } else {
            out.append(c);
        }
    }
    return out.toString();
}

Dayanarak https://stackoverflow.com/a/8838023/1199155 (amp orada eksik). Http://www.w3.org/TR/html4/sgml/entities.html uyarınca, if yan tümcesinde işaretlenen dört karakter 128'in altında yalnızca tek karakterdir.


Güzel. Kodlamaların "html sürümlerini" kullanmaz (örnek: "á", "& # 225;" yerine "& aacute;" olur), ancak sayısal olanlar IE7'de bile çalıştığından sanmıyorum endişelenmek zorunda. Teşekkürler.
nonzaprej

OP ilgili 4 karakterden kaçmak istediğinde neden tüm bu karakterleri kodluyorsunuz? CPU ve bellek harcıyorsunuz.
David Balažic

1
Kesme işaretini unuttun. Böylece insanlar, bu kodun özellik değerlerinden kaçmak için kullanıldığı her yere tırnaksız nitelikler enjekte edebilir.
David Balažic

45

Apache Commons Lang kütüphanesinin daha yeni bir sürümü var ve farklı bir paket adı kullanıyor (org.apache.commons.lang3). Artık StringEscapeUtilsfarklı türdeki dokümanlardan kaçmak için farklı statik yöntemler var ( http://commons.apache.org/proper/commons-lang/javadocs/api-3.0/index.html ). HTML sürüm 4.0 dizesinden kaçmak için:

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");

3
Ne yazık ki HTML 5 için hiçbir şey yok ve Apache belgeleri HTML 5 için escapeHtml4 kullanmanın uygun olup olmadığını da belirtmiyor
Paul Vincent Craven

43

Google Guava'yı kullananlar için:

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);

40

Android'de (API 16 veya üstü) şunları yapabilirsiniz:

Html.escapeHtml(textToScape);

veya daha düşük API için:

TextUtils.htmlEncode(textToScape);

escapeHtmlBunun yerine kullanmak için herhangi bir neden var mı htmlEncode?
Muz

2
Ayrıca bu ikisi arasındaki fark hakkındaki sorumu da görün . (@Muz)
JonasCz - Monica'yı

37

Buna dikkat et. Bir HTML belgesinde birkaç farklı 'bağlam' vardır: Bir öğenin içinde, alıntılanmış özellik değeri, alıntılanmamış özellik değeri, URL özelliği, javascript, CSS, vb ... Her biri için farklı bir kodlama yöntemi kullanmanız gerekir. bunlar Siteler Arası Komut Dizilerini (XSS) önlemek için kullanılır. Kontrol OWASP XSS Önleme Hile Sheet bu bağlamlarda her birine ilişkin ayrıntılar için. Bu bağlamların her biri için kaçış yöntemlerini OWASP ESAPI kütüphanesinde bulabilirsiniz - https://github.com/ESAPI/esapi-java-legacy .


6
Çıktıyı kodlamak istediğiniz bağlamın çok önemli olduğuna dikkat ettiğiniz için teşekkür ederiz . "Kodlama" terimi de "kaçış" kelimesinden çok daha uygun bir fiildir. Escape, " bu dizeyi şu şekilde nasıl kodlayabilirim : bir XHTML özniteliği / SQL sorgu parametresi / PostScript yazdırma dizesi / CSV çıktı alanı yerine" bir tür özel saldırı anlamına gelir
Roboprog

5
'Encode' ve 'escape' her ikisi de bunu tanımlamak için yaygın olarak kullanılmaktadır. Genellikle "kaçış" terimi, sözdizimsel olarak alakalı bir karakterden önce, ters eğik çizgi ile bir tırnak karakteri kaçmak gibi bir "kaçış karakteri" eklemek olduğunda kullanılır. "" Kodlama "terimi, % 22 teklif karakterini kodlayan URL veya & # x22 veya @quot olarak kodlayan HTML varlığı gibi farklı bir forma dönüştürür
Jeff Williams


1
Size biraz googling kaydetmek için Encoder sınıfını static.javadoc.io/org.owasp.esapi/esapi/2.0.1/org/owasp/esapi/…
Jakub Bochenski

14

Bazı amaçlar için, HtmlUtils :

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

1
İlkbahardan HtmlUtils yorum: * <p> Dize kaçan yardımcı programları kapsamlı bir set için * Apache Commons Lang ve onun StringEscapeUtils sınıfını düşünün. * Commons Lang'da sadece HTML çıkışından dolayı çalışma zamanı bağımlılığını önlemek için bu sınıfı burada kullanmıyoruz. Dahası, Spring'in * HTML çıkışları daha esnek ve% 100 HTML 4.0 uyumludur. Projenizde zaten Apache müşterilerini kullanıyorsanız, muhtemelen apache'den StringEscapeUtils'i kullanmalısınız
andreyro

10

@ Dfa yanıtı org.apache.commons.lang.StringEscapeUtils.escapeHtmlgüzel olsa da ve ben geçmişte kullandığım HTML (veya XML) öznitelikleri kaçmak için kullanılmamalıdır aksi takdirde boşluk normalleştirilecektir (yani tüm bitişik boşluk karakterleri tek bir boşluk haline gelir).

Bunu biliyorum çünkü boşluk korunmayan öznitelikler için kütüphaneme (JATL) karşı açılan hatalar oldu. Böylece (copy n 'paste) sınıfında (bunlardan bazılarını JDOM'dan çaldım) niteliklerden ve eleman içeriğinden kaçışını ayıran bir düşüş var .

Bu geçmişte çok önemli olmasa da (uygun özellik kaçış), HTML5'in data-özellik kullanımının kullanımı göz önüne alındığında giderek daha fazla ilgi görmektedir .


9

org.apache.commons.lang3.StringEscapeUtils artık kullanımdan kaldırıldı. Şimdi org.apache.commons.text.StringEscapeUtils kullanmanız gerekir

    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-text</artifactId>
        <version>${commons.text.version}</version>
    </dependency>

1

Çoğu kütüphane, UTF-8 dünyasında istediğiniz gibi olmayan yüzlerce sembol ve binlerce ASCII olmayan karakter de dahil olmak üzere ellerinden gelebilecek her şeyi kaçırmayı öneriyor.

Ayrıca, Jeff Williams'ın belirttiği gibi, tek bir “kaçış HTML” seçeneği yoktur, birkaç bağlam vardır.

Hiçbir zaman alıntılanmamış nitelikleri kullanmadığınızı ve farklı bağlamların mevcut olduğunu göz önünde bulundurarak, kendi sürümümü yazdı:

private static final long BODY_ESCAPE =
        1L << '&' | 1L << '<' | 1L << '>';
private static final long DOUBLE_QUOTED_ATTR_ESCAPE =
        1L << '"' | 1L << '&' | 1L << '<' | 1L << '>';
private static final long SINGLE_QUOTED_ATTR_ESCAPE =
        1L << '"' | 1L << '&' | 1L << '\'' | 1L << '<' | 1L << '>';

// 'quot' and 'apos' are 1 char longer than '#34' and '#39' which I've decided to use
private static final String REPLACEMENTS = "&#34;&amp;&#39;&lt;&gt;";
private static final int REPL_SLICES = /*  |0,   5,   10,  15, 19, 23*/
        5<<5 | 10<<10 | 15<<15 | 19<<20 | 23<<25;
// These 5-bit numbers packed into a single int
// are indices within REPLACEMENTS which is a 'flat' String[]

private static void appendEscaped(
        StringBuilder builder,
        CharSequence content,
        long escapes // pass BODY_ESCAPE or *_QUOTED_ATTR_ESCAPE here
) {
    int startIdx = 0, len = content.length();
    for (int i = 0; i < len; i++) {
        char c = content.charAt(i);
        long one;
        if (((c & 63) == c) && ((one = 1L << c) & escapes) != 0) {
        // -^^^^^^^^^^^^^^^   -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        // |                  | take only dangerous characters
        // | java shifts longs by 6 least significant bits,
        // | e. g. << 0b110111111 is same as >> 0b111111.
        // | Filter out bigger characters

            int index = Long.bitCount(SINGLE_QUOTED_ATTR_ESCAPE & (one - 1));
            builder.append(content, startIdx, i /* exclusive */)
                    .append(REPLACEMENTS,
                            REPL_SLICES >>> 5*index & 31,
                            REPL_SLICES >>> 5*(index+1) & 31);
            startIdx = i + 1;
        }
    }
    builder.append(content, startIdx, len);
}

Çizgi uzunluğu sınırı olmadan Gist'ten kopya yapıştırmayı düşünün .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.