DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Open Source: A Pathway To Personal and Professional Growth
  • Enhancing Software Quality with Checkstyle and PMD: A Practical Guide
  • Linting Excellence: How Black, isort, and Ruff Elevate Python Code Quality
  • Mastering GitHub Copilot: Top 25 Metrics Redefining Developer Productivity

Trending

  • Unlocking Data with Language: Real-World Applications of Text-to-SQL Interfaces
  • Infrastructure as Code (IaC) Beyond the Basics
  • Blue Skies Ahead: An AI Case Study on LLM Use for a Graph Theory Related Application
  • Ethical AI in Agile

Cross-Site Scripting (XSS) Attack Remediation

Learn more about prevention and remediation after a cross-site scripting attack.

By 
Mohamed Sanaulla user avatar
Mohamed Sanaulla
·
May. 08, 19 · Analysis
Likes (3)
Comment
Save
Tweet
Share
37.0K Views

Join the DZone community and get the full member experience.

Join For Free

For more details on XSS attacks, please refer to OWASP and this OWASP Prevention cheat sheet.

Preventing XSS

Various factors should be considered while acting on XSS Attacks, for example:

  • Input type in the HTTP request
  • Locations of the HTML document where data would be included

Note

  • A defense that works in one context (such as an HTML attribute) might not work in another context (such as a JavaScript variable assignment)
  • A defense that works with one kind of input (such as input validation and output encoding for a username) will not work with other kinds of input (such as sanitization for untrusted HTML).

We need to use a different output encoding function based on where you are inserting untrusted data into the webpage!

OWASP Java Encoder Project

<dependency>
    <groupId>org.owasp.encoder</groupId>
    <artifactId>encoder</artifactId>
    <version>1.2.1</version>
</dependency>
<dependency>
    <groupId>org.owasp.encoder</groupId>
    <artifactId>encoder-jsp</artifactId>
    <version>1.2.1</version>
</dependency>


Here are a few examples of different contexts in an HTML page in a JSP:

Encoding

HTML

The following encoding functions are used to safely place untrusted data into different locations of an HTML document.

API Coments
Encode.forHtml(UNTRUSTED) If you are unsure, which one to use, you can use this in HTML context
Encode.forHtmlAttribute(UNTRUSTED)
Encode.forHtmlContent(UNTRUSTED)
Encode.forHtmlUnquotedAttribute(UNTRUSTED)

JavaScript

The following encoding functions are used to safely place untrusted data into different locations of JavaScript code.

API Comments
Encode.forJavaScript(UNTRUSTED) If you are unsure, which one to use, you can use this in JavaScript context
Encode.forJavaScriptAttribute(UNTRUSTED)
Encode.forJavaScriptBlock(UNTRUSTED)
Encode.forJavaScriptSource(UNTRUSTED)

CSS

The following encoding functions are used to safely place untrusted data into different locations of dynamic CSS code.

API Comments

Encode.forCssString(UNTRUSTED)

<div>Encode.forCssString(UNTRUSTED) %>”>

Encode.forCssUrl(UNTRUSTED)

<div>Encode.forCssUrl(UNTRUSTED) %>”>

XML

API Comments
Encode.forXML(UNTRUSTED)
Encode.forXMLContent(UNTRUSTED)
Encode.forXMLAttribute(UNTRUSTED)
Encode.forXMLComment(UNTRUSTED)
Encode.forCDATA(UNTRUSTED)

Tag Lib

Prefer tag libs while working with jsps:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<%@taglib prefix="e" uri="https://www.owasp.org/index.php/OWASP_Java_Encoder_Project" %>
<html>
<head>
<title><e:forHtml value="${param.title}" /></title>
</head>
<body>
<h1>${e:forHtml(param.data)}</h1>
</body> P


For more details, refer to the OWASP Java Encoder Project Docs.

Wrapper Class

import javax.servlet.http.HttpServletRequest;
  
import org.owasp.encoder.Encode;
  
public class SafeDataBuilder {
  
    private String paramVal = null;
  
    private SafeDataBuilder(HttpServletRequest request, String paramName) {
        String val = getValue(request, paramName);
        this.paramVal = cleanValue(val);
    }
  
    private String cleanValue(String val) {
        String result = val;
        if (val != null && val.length() > SecurityConstants.MAX_HTTP_PARAM_LENGTH) {
            result = val.substring(0, SecurityConstants.MAX_HTTP_PARAM_LENGTH);
        }
        return result;
    }
  
    private String getValue(HttpServletRequest request, String paramName) {
        String val = request.getParameter(paramName);
  
        if (val == null) {
            Object attr = request.getAttribute(paramName);
            if (attr instanceof String) {
                val = (String) attr;
            }
            if (attr instanceof Boolean) {
                val = attr.toString();
            }
        }
        return val;
    }
  
    public static SafeDataBuilder requestParam(HttpServletRequest request, String paramName) {
        return new SafeDataBuilder(request, paramName);
    }
  
    public SafeDataBuilder defaultValue(String val) {
        if (this.paramVal == null) {
            this.paramVal = val;
        }
        return this;
    }
      
    public SafeDataBuilder trim() {
        if (this.paramVal != null) {
            this.paramVal = paramVal.trim();
        }
        return this;
    }
  
    public SafeDataBuilder forHtml() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forHtml(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forHtmlContent() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forHtml(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forHtmlAttribute() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forHtml(this.paramVal);
        }
        return this;
    }
      
   public SafeDataBuilder forFormActionAttribute() {
        if (this.paramVal != null) {           
            this.paramVal = Encode.forHtmlAttribute(cleanJsAttribute(this.paramVal));
        }
        return this;
    }
  
    private String cleanJsAttribute(String action) {
        String result = action;
        String cleansed = action.trim().toLowerCase();
        if (cleansed.startsWith("javascript")) {
            result = cleansed.substring(10);
        }
        return result;
    }
    public SafeDataBuilder forJavaScript() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forJavaScript(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forJavaScriptAttribute() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forJavaScriptAttribute(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forJavaScriptBlock() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forJavaScriptBlock(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forJavaScriptSource() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forJavaScriptSource(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forCssString() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forCssString(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forCssUrl() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forCssUrl(this.paramVal);
        }
        return this;
    }
  
    public SafeDataBuilder forUriComponent() {
        if (this.paramVal != null) {
            this.paramVal = Encode.forUriComponent(this.paramVal);
        }
        return this;
    }
  
    public String get() {
        return this.paramVal;
    }
  
  
    public String getQuoted() {
        return "'" + this.paramVal + "'";
    }
}


Usage

String paramVal = SafeDataBuilder.requestParam(request, "paramName").forHtml().get();
String paramVal = SafeDataBuilder.requestParam(request, "paramName").defaultValue("def").forHtml().get();
String paramVal = SafeDataBuilder.requestParam(request, "paramName").defaultValue("def").trim().forHtml().get();


Solution

Refer to the project for more details:

  • Define a config for each page.
  • The config describes what are all parameters (and XSS type) used by the page
  • Configure an XSS filter (XSSFilter) for every request, which wraps an httpservelet request (XSSRequestWrapper).
  • Eventually, every page has XSSRequestWrapper as HTTPServletRequest, whenever getParameter happens, config is read to the determine the XSS type, and data is stripped accordingly.
  • Further, we may have to define one more method in XSSRequestWrapper getParameter (name, type) in case the need arises.
  • Further, we may have to define one more method in XSSRequestWrapper getOriginalParameter (name) in case if the need arises.
  • Further by default, for each parameter p, there should other for example p_xss_s_xss_type (for each  xss_type)

References

  • OWASP Java Encoder
  • OWASP Java Encoder Project Docs
code style

Published at DZone with permission of Mohamed Sanaulla, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Open Source: A Pathway To Personal and Professional Growth
  • Enhancing Software Quality with Checkstyle and PMD: A Practical Guide
  • Linting Excellence: How Black, isort, and Ruff Elevate Python Code Quality
  • Mastering GitHub Copilot: Top 25 Metrics Redefining Developer Productivity

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!