Wie kann ich XSS-Angriffe in einer JSP / Servlet-Webanwendung verhindern?
Antworten:
XSS kann in JSP durch Verwendung des JSTL- <c:out>
Tags oder der fn:escapeXml()
EL-Funktion verhindert werden, wenn benutzergesteuerte Eingaben (erneut) angezeigt werden . Dies umfasst Anforderungsparameter, Header, Cookies, URL, Text usw. Alles, was Sie aus dem Anforderungsobjekt extrahieren. Auch die benutzergesteuerte Eingabe von früheren Anforderungen, die in einer Datenbank gespeichert sind, muss während der erneuten Anzeige maskiert werden.
Zum Beispiel:
<p><c:out value="${bean.userControlledValue}"></p>
<p><input name="foo" value="${fn:escapeXml(param.foo)}"></p>
Dies wird Escape - Zeichen , die das gerenderte HTML malform können wie <
, >
, "
, '
und &
in HTML / XML - Entitäten wie <
, >
, "
, '
und &
.
Beachten Sie, dass Sie sie nicht im Java-Code (Servlet) maskieren müssen, da sie dort harmlos sind. Einige können sich entscheiden , sie während zu entkommen Anfrage Verarbeitung (wie Sie in Servlet oder Filtern zu tun) statt Antwortverarbeitung (wie Sie in JSP zu tun), aber auf diese Weise riskieren Sie, dass die Daten unnötig bekommen doppelten Escape (zB &
wird &amp;
statt &
und letztendlich würde der Endbenutzer sehen&
angezeigt werden) oder dass die in der DB gespeicherten Daten nicht mehr portierbar sind (z. B. beim Exportieren von Daten nach JSON, CSV, XLS, PDF usw., für die überhaupt kein HTML-Escape erforderlich ist). Sie verlieren auch die soziale Kontrolle, weil Sie nicht mehr wissen, was der Benutzer tatsächlich ausgefüllt hat. Als Site-Administrator möchten Sie wirklich wissen, welche Benutzer / IPs versuchen, XSS auszuführen, damit Sie leicht nachverfolgen können sie und ergreifen Maßnahmen entsprechend. Das Entkommen während der Anforderungsverarbeitung sollte nur dann und nur dann als neuester Ausweg verwendet werden, wenn Sie wirklich ein Zugunglück einer schlecht entwickelten Legacy-Webanwendung in kürzester Zeit beheben müssen. Dennoch sollten Sie Ihre JSP-Dateien letztendlich neu schreiben, um XSS-sicher zu werden.
Wenn Sie möchten , benutzergesteuerte Eingabe als HTML erneut anzuzeigen , wobei Sie nur eine bestimmte Untergruppe von HTML - Tags wie ermöglichen möchten <b>
, <i>
, <u>
usw, dann müssen Sie die Eingabe mit einer weißen Liste sanieren. Sie können hierfür einen HTML-Parser wie Jsoup verwenden . Viel besser ist es jedoch, eine benutzerfreundliche Markup-Sprache wie Markdown einzuführen (die auch hier bei Stack Overflow verwendet wird). Dann können Sie hierfür einen Markdown-Parser wie CommonMark verwenden . Es hat auch HTML-Bereinigungsfunktionen eingebaut. Siehe auch Markdown oder HTML .
Das einzige Problem auf der Serverseite in Bezug auf Datenbanken ist die Verhinderung der SQL-Injektion . Sie müssen sicherstellen, dass Sie niemals benutzergesteuerte Eingaben direkt in der SQL- oder JPQL-Abfrage mit Zeichenfolgen verketten und dass Sie vollständig parametrisierte Abfragen verwenden. In JDBC-Begriffen bedeutet dies, dass Sie PreparedStatement
anstelle von verwenden sollten Statement
. Verwenden Sie in JPA-Begriffen Query
.
Eine Alternative wäre die Migration von JSP / Servlet auf das MVC-Framework JSF von Java EE . Es hat überall XSS (und CSRF!) Prävention eingebaut. Siehe auch CSRF-, XSS- und SQL Injection-Angriffsprävention in JSF .
"SELECT ... WHERE SOMEVAL = " + someval
anstatt wie gezeigt parametrisierte Abfragen zu verwenden. Kein ORM kann sich vor solchen Entwicklerfehlern schützen.
Das How-to-Prevent-xss wurde mehrmals gefragt. In StackOverflow finden Sie viele Informationen. Außerdem enthält die OWASP-Website einen XSS-Präventions-Spickzettel , den Sie durchgehen sollten.
In den zu verwendenden Bibliotheken hat die ESAPI-Bibliothek von OWASP eine Java -Variante . Das solltest du ausprobieren. Außerdem bietet jedes Framework, das Sie verwenden, einen gewissen Schutz gegen XSS. Auch hier enthält die OWASP-Website Informationen zu den beliebtesten Frameworks. Ich würde daher empfehlen, deren Website zu durchsuchen.
Ich hatte großes Glück mit OWASP Anti-Samy und einem AspectJ-Berater für alle meine Federregler, die XSS daran hindern, einzusteigen.
public class UserInputSanitizer {
private static Policy policy;
private static AntiSamy antiSamy;
private static AntiSamy getAntiSamy() throws PolicyException {
if (antiSamy == null) {
policy = getPolicy("evocatus-default");
antiSamy = new AntiSamy();
}
return antiSamy;
}
public static String sanitize(String input) {
CleanResults cr;
try {
cr = getAntiSamy().scan(input, policy);
} catch (Exception e) {
throw new RuntimeException(e);
}
return cr.getCleanHTML();
}
private static Policy getPolicy(String name) throws PolicyException {
Policy policy =
Policy.getInstance(Policy.class.getResourceAsStream("/META-INF/antisamy/" + name + ".xml"));
return policy;
}
}
Den AspectJ-Advisor erhalten Sie in diesem Stackoverflow-Beitrag
Ich denke, dies ist ein besserer Ansatz als c: out, insbesondere wenn Sie viel Javascript verwenden.
Die Verwaltung von XSS erfordert mehrere Überprüfungen, Daten von der Clientseite.
Ich würde empfehlen, regelmäßig mit einem automatisierten Tool auf Schwachstellen zu testen und alle gefundenen Probleme zu beheben. Es ist viel einfacher, eine Bibliothek vorzuschlagen, um bei einer bestimmten Sicherheitsanfälligkeit zu helfen, als bei allen XSS-Angriffen im Allgemeinen.
Skipfish ist ein Open-Source-Tool von Google, das ich untersucht habe: Es findet ziemlich viel Material und scheint es wert zu sein, es zu verwenden.
Es gibt keine einfache, sofort einsatzbereite Lösung gegen XSS. Die OWASP ESAPI-API bietet Unterstützung für das Escape, was sehr nützlich ist, und sie verfügt über Tag-Bibliotheken.
Mein Ansatz war es, die Stuts 2-Tags auf folgende Weise zu erweitern.
Wenn Sie die Klassen in Schritt 1 nicht ändern möchten, besteht ein anderer Ansatz darin, die ESAPI-Tags in die Freemarker-Vorlagen zu importieren und bei Bedarf zu maskieren. Wenn Sie dann als: property-Tag in Ihrer JSP verwenden müssen, schließen Sie es mit und ESAPI-Tag ein.
Ich habe hier eine ausführlichere Erklärung geschrieben.
http://www.nutshellsoftware.org/software/securing-struts-2-using-esapi-part-1-securing-outputs/
Ich bin damit einverstanden, dass es nicht ideal ist, Eingaben zu entkommen.
Meine persönliche Meinung ist, dass Sie die Verwendung von JSP / ASP / PHP / etc-Seiten vermeiden sollten. Ausgabe stattdessen an eine SAX-ähnliche API (nur zum Aufrufen und nicht zum Behandeln vorgesehen). Auf diese Weise gibt es eine einzelne Schicht, die eine wohlgeformte Ausgabe erzeugen muss.
Wenn Sie automatisch alle JSP-Variablen maskieren möchten, ohne jede Variable explizit umbrechen zu müssen, können Sie einen EL-Resolver verwenden, wie hier beschrieben mit vollständiger Quelle und einem Beispiel (JSP 2.0 oder neuer) , der hier ausführlicher erläutert wird :
Wenn Sie beispielsweise den oben genannten EL-Resolver verwenden, bleibt Ihr JSP-Code unverändert, aber jede Variable wird vom Resolver automatisch maskiert
...
<c:forEach items="${orders}" var="item">
<p>${item.name}</p>
<p>${item.price}</p>
<p>${item.description}</p>
</c:forEach>
...
Wenn Sie im Frühjahr standardmäßig das Escape erzwingen möchten, können Sie dies ebenfalls berücksichtigen, aber es entgeht nicht den EL-Ausdrücken, sondern nur der Tag-Ausgabe.
http://forum.springsource.org/showthread.php?61418-Spring-cross-site-scripting&p=205646#post205646
Hinweis: Ein weiterer Ansatz zur EL-Escape-Methode, bei dem XSL-Transformationen zur Vorverarbeitung von JSP-Dateien verwendet werden, finden Sie hier:
http://therning.org/niklas/2007/09/preprocessing-jsp-files-to-automatically-escape-el-expressions/
<enhance:out escapeXml="false">
wie im Artikel beschrieben einpacken.
Wenn Sie sicherstellen möchten, dass Ihr $
Operator nicht unter XSS-Hack leidet, können ServletContextListener
Sie dort einige Überprüfungen durchführen.
Die vollständige Lösung finden Sie unter: http://pukkaone.github.io/2011/01/03/jsp-cross-site-scripting-elresolver.html
@WebListener
public class EscapeXmlELResolverListener implements ServletContextListener {
private static final Logger LOG = LoggerFactory.getLogger(EscapeXmlELResolverListener.class);
@Override
public void contextInitialized(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener initialized ...");
JspFactory.getDefaultFactory()
.getJspApplicationContext(event.getServletContext())
.addELResolver(new EscapeXmlELResolver());
}
@Override
public void contextDestroyed(ServletContextEvent event) {
LOG.info("EscapeXmlELResolverListener destroyed");
}
/**
* {@link ELResolver} which escapes XML in String values.
*/
public class EscapeXmlELResolver extends ELResolver {
private ThreadLocal<Boolean> excludeMe = new ThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return Boolean.FALSE;
}
};
@Override
public Object getValue(ELContext context, Object base, Object property) {
try {
if (excludeMe.get()) {
return null;
}
// This resolver is in the original resolver chain. To prevent
// infinite recursion, set a flag to prevent this resolver from
// invoking the original resolver chain again when its turn in the
// chain comes around.
excludeMe.set(Boolean.TRUE);
Object value = context.getELResolver().getValue(
context, base, property);
if (value instanceof String) {
value = StringEscapeUtils.escapeHtml4((String) value);
}
return value;
} finally {
excludeMe.remove();
}
}
@Override
public Class<?> getCommonPropertyType(ELContext context, Object base) {
return null;
}
@Override
public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base){
return null;
}
@Override
public Class<?> getType(ELContext context, Object base, Object property) {
return null;
}
@Override
public boolean isReadOnly(ELContext context, Object base, Object property) {
return true;
}
@Override
public void setValue(ELContext context, Object base, Object property, Object value){
throw new UnsupportedOperationException();
}
}
}
Nochmals: Dies schützt nur die $
. Bitte beachten Sie auch andere Antworten.