关于pdf文件xss攻击问题,配置xssFilter方法

1.pom.xml添加依赖

	<dependency>
		<groupId>org.owasp.esapi</groupId>
		<artifactId>esapi</artifactId>
		<version>2.5.1.0</version>
	</dependency>
	<dependency>
		<groupId>org.owasp.antisamy</groupId>
		<artifactId>antisamy</artifactId>
		<version>1.7.2</version>
	</dependency>

依赖下载地址

https://repo1.maven.org/maven2/

拦截器文件详细:

ReplaceRequestBodyFilter

// An highlighted block
package com.finegold.xssfilter;

import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class ReplaceRequestBodyFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String contentType = request.getContentType();
        if (null != contentType && contentType.contains("multipart/")) {//说明是文件上传
            XSSCommonsMultipartResolver commonsMultipartResolver = new XSSCommonsMultipartResolver();
            XSSMultipartHttpServletRequest resolveMultipart = (XSSMultipartHttpServletRequest) commonsMultipartResolver.resolveMultipart(request);
            filterChain.doFilter(resolveMultipart, response);
        } else {
            filterChain.doFilter(request, response);
        }
    }
}

XSSCommonsMultipartResolver

package com.finegold.xssfilter;

import org.springframework.context.annotation.Bean;
import org.springframework.util.Assert;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.http.HttpServletRequest;
import java.nio.charset.StandardCharsets;

public class XSSCommonsMultipartResolver extends CommonsMultipartResolver {
    private boolean resolveLazily = false;
    public XSSCommonsMultipartResolver() {
        super();
    }

    @Override
    public void setResolveLazily(boolean resolveLazily) {
        this.resolveLazily = resolveLazily;
    }

    @Bean(name = "multipartResolver")
    public CommonsMultipartResolver multipartResolver() {
        CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
        multipartResolver.setDefaultEncoding(StandardCharsets.UTF_8.name());
        multipartResolver.setMaxUploadSize(-1);
        return multipartResolver;
    }

    @Override
    public MultipartHttpServletRequest resolveMultipart(final HttpServletRequest request) throws MultipartException {
        Assert.notNull(request, "Request must not be null");
        if (this.resolveLazily) {
            return new XSSMultipartHttpServletRequest(request) {
                @Override
                protected void initializeMultipart() {
                    MultipartParsingResult parsingResult = parseRequest(request);
                    setMultipartFiles(parsingResult.getMultipartFiles());
                    setMultipartParameters(parsingResult.getMultipartParameters());
                    setMultipartParameterContentTypes(parsingResult.getMultipartParameterContentTypes());
                }
            };
        } else {
            MultipartParsingResult parsingResult = parseRequest(request);
            return new XSSMultipartHttpServletRequest(request, parsingResult.getMultipartFiles(),
                    parsingResult.getMultipartParameters(), parsingResult.getMultipartParameterContentTypes());
        }
    }
}


XSSMultipartHttpServletRequest

package com.finegold.xssfilter;

import com.finegold.utils.exception.BaseException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.owasp.esapi.ESAPI;
import org.springframework.util.MultiValueMap;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import org.springframework.web.multipart.support.DefaultMultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Slf4j
public class XSSMultipartHttpServletRequest extends DefaultMultipartHttpServletRequest {
    public XSSMultipartHttpServletRequest(HttpServletRequest request, MultiValueMap<String, MultipartFile> mpFiles, Map<String, String[]> mpParams, Map<String, String> mpParamContentTypes) {
        super(request);
        setMultipartFiles(mpFiles);
        setMultipartParameters(mpParams);
        setMultipartParameterContentTypes(mpParamContentTypes);
    }

    public XSSMultipartHttpServletRequest(HttpServletRequest request) {
        super(request);
    }

    @Override
    protected MultiValueMap<String, MultipartFile> getMultipartFiles() {
        MultiValueMap<String, MultipartFile> result = super.getMultipartFiles();
        Set<String> keySet = result.keySet();
        for (String key : keySet) {
            List<MultipartFile> fileList = result.get(key);
            List<MultipartFile> multipartFiles = new ArrayList<>();
            for (MultipartFile file : fileList) {

                if (file!= null && file.getOriginalFilename()!= null && !file.getContentType().contains("image")) {
                    String fileName = file.getOriginalFilename();
                    try {
                        InputStream inputStream = file.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                        FileItem fileItem = new DiskFileItemFactory().createItem("file", file.getContentType(), false, fileName);
                        OutputStream os = fileItem.getOutputStream();
                        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os));
                        while (bufferedReader.ready()){
                            String line = bufferedReader.readLine();
                            writer.write(stripXSS(line));
                            writer.newLine();
                        }
                        writer.flush();
                        CommonsMultipartFile commonsMultipartFile = new CommonsMultipartFile(fileItem);
                        multipartFiles.add(commonsMultipartFile);

                    } catch (IOException e) {
                        log.error("修改请求流时错误:", e);
                    }
                } else if (file!= null && file.getOriginalFilename()!= null && file.getContentType().startsWith("image")) {
                    try {
                        InputStream inputStream = file.getInputStream();
                        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
                        while (bufferedReader.ready()){
                            String line = bufferedReader.readLine();
                            if (StringUtils.hasText(line) && !validatorXSS(line)) {
                                throw new BaseException("无效图片,请换一张");
                            }
                        }
                        multipartFiles.add(file);

                    } catch (IOException e) {
                        log.error("修改请求流时错误:", e);
                    }
                } else {
                    multipartFiles.add(file);
                }
            }

            result.put(key, multipartFiles);

        }
        return result;
    }

    private String stripXSS(String value) {
        if (value != null) {
            // NOTE: It's highly recommended to use the ESAPI library and uncomment the following line to
            // avoid encoded attacks.
            value = ESAPI.encoder().canonicalize(value);

            // Avoid null characters
            value = value.replaceAll("", "");

            // Avoid anything between script tags
            Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid anything between pdf script tags
            scriptPattern = Pattern.compile("javascript", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid anything in a src='...' type of expression
            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Remove any lonesome </script> tag
            scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Remove any lonesome <script ...> tag
            scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid eval(...) expressions
            scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid expression(...) expressions
            scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid javascript:... expressions
            scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid vbscript:... expressions
            scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid php:... expressions
            scriptPattern = Pattern.compile("<\\?php(.*?)\\?>", Pattern.CASE_INSENSITIVE);
            value = scriptPattern.matcher(value).replaceAll("");

            // Avoid οnlοad= expressions
            scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
            value = scriptPattern.matcher(value).replaceAll("");
        }
        return value;
    }

    private boolean validatorXSS(String value) {
        value = ESAPI.encoder().canonicalize(value);

        // Avoid anything between script tags
        Pattern scriptPattern = Pattern.compile("<script>(.*?)</script>", Pattern.CASE_INSENSITIVE);
        Matcher matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Avoid anything between pdf script tags
        scriptPattern = Pattern.compile("javascript", Pattern.CASE_INSENSITIVE);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Avoid anything in a src='...' type of expression
        scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\'(.*?)\\\'", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        scriptPattern = Pattern.compile("src[\r\n]*=[\r\n]*\\\"(.*?)\\\"", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Remove any lonesome </script> tag
        scriptPattern = Pattern.compile("</script>", Pattern.CASE_INSENSITIVE);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Remove any lonesome <script ...> tag
        scriptPattern = Pattern.compile("<script(.*?)>", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Avoid eval(...) expressions
        scriptPattern = Pattern.compile("eval\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Avoid expression(...) expressions
        scriptPattern = Pattern.compile("expression\\((.*?)\\)", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Avoid javascript:... expressions
        scriptPattern = Pattern.compile("javascript:", Pattern.CASE_INSENSITIVE);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Avoid vbscript:... expressions
        scriptPattern = Pattern.compile("vbscript:", Pattern.CASE_INSENSITIVE);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }
        // Avoid php:... expressions
        scriptPattern = Pattern.compile("<\\?php(.*?)\\?>", Pattern.CASE_INSENSITIVE);
        matcher = scriptPattern.matcher(value);
        if (matcher.find()){
            return false;
        }

        // Avoid οnlοad= expressions
        scriptPattern = Pattern.compile("onload(.*?)=", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE | Pattern.DOTALL);
        matcher = scriptPattern.matcher(value);
        return !matcher.find();
    }
}

关于ESAPI所需配置文件

ESAPI.properties

#
# OWASP Enterprise Security API (ESAPI) Properties file -- PRODUCTION Version
# 
# This file is part of the Open Web Application Security Project (OWASP)
# Enterprise Security API (ESAPI) project. For details, please see
# https://owasp.org/www-project-enterprise-security-api/
#
# Copyright (c) 2008,2009 - The OWASP Foundation
#
# DISCUSS: This may cause a major backwards compatibility issue, etc. but
#		   from a name space perspective, we probably should have prefaced
#		   all the property names with ESAPI or at least OWASP. Otherwise
#		   there could be problems is someone loads this properties file into
#		   the System properties.  We could also put this file into the
#		   esapi.jar file (perhaps as a ResourceBundle) and then allow an external
#		   ESAPI properties be defined that would overwrite these defaults.
#		   That keeps the application's properties relatively simple as usually
#		   they will only want to override a few properties. If looks like we
#		   already support multiple override levels of this in the
#		   DefaultSecurityConfiguration class, but I'm suggesting placing the
#		   defaults in the esapi.jar itself. That way, if the jar is signed,
#		   we could detect if those properties had been tampered with. (The
#		   code to check the jar signatures is pretty simple... maybe 70-90 LOC,
#		   but off course there is an execution penalty (similar to the way
#		   that the separate sunjce.jar used to be when a class from it was
#		   first loaded). Thoughts?
###############################################################################
#
# WARNING: Operating system protection should be used to lock down the .esapi
# resources directory and all the files inside and all the directories all the
# way up to the root directory of the file system.  Note that if you are using
# file-based implementations, that some files may need to be read-write as they
# get updated dynamically.
#
#===========================================================================
# ESAPI Configuration
#
# If true, then print all the ESAPI properties set here when they are loaded.
# If false, they are not printed. Useful to reduce output when running JUnit tests.
# If you need to troubleshoot a properties related problem, turning this on may help.
# This is 'false' in the src/test/resources/.esapi version. It is 'true' by
# default for reasons of backward compatibility with earlier ESAPI versions.
ESAPI.printProperties=true

# ESAPI is designed to be easily extensible. You can use the reference implementation
# or implement your own providers to take advantage of your enterprise's security
# infrastructure. The functions in ESAPI are referenced using the ESAPI locator, like:
#
#    String ciphertext =
#		ESAPI.encryptor().encrypt("Secret message");   // Deprecated in 2.0
#    CipherText cipherText =
#		ESAPI.encryptor().encrypt(new PlainText("Secret message")); // Preferred
#
# Below you can specify the classname for the provider that you wish to use in your
# application. The only requirement is that it implement the appropriate ESAPI interface.
# This allows you to switch security implementations in the future without rewriting the
# entire application.
#
# ExperimentalAccessController requires ESAPI-AccessControlPolicy.xml in .esapi directory
ESAPI.AccessControl=org.owasp.esapi.reference.DefaultAccessController
# FileBasedAuthenticator requires users.txt file in .esapi directory
ESAPI.Authenticator=org.owasp.esapi.reference.FileBasedAuthenticator
ESAPI.Encoder=org.owasp.esapi.reference.DefaultEncoder
ESAPI.Encryptor=org.owasp.esapi.reference.crypto.JavaEncryptor

ESAPI.Executor=org.owasp.esapi.reference.DefaultExecutor
ESAPI.HTTPUtilities=org.owasp.esapi.reference.DefaultHTTPUtilities
ESAPI.IntrusionDetector=org.owasp.esapi.reference.DefaultIntrusionDetector
ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
# To use the new SLF4J logger in ESAPI (see GitHub issue #129), set
#    ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory
# and do whatever other normal SLF4J configuration that you normally would do for your application.
ESAPI.Randomizer=org.owasp.esapi.reference.DefaultRandomizer
ESAPI.Validator=org.owasp.esapi.reference.DefaultValidator

#===========================================================================
# ESAPI Authenticator
#
Authenticator.AllowedLoginAttempts=3
Authenticator.MaxOldPasswordHashes=13
Authenticator.UsernameParameterName=username
Authenticator.PasswordParameterName=password
# RememberTokenDuration (in days)
Authenticator.RememberTokenDuration=14
# Session Timeouts (in minutes)
Authenticator.IdleTimeoutDuration=20
Authenticator.AbsoluteTimeoutDuration=120

#===========================================================================
# ESAPI Encoder
#
# ESAPI canonicalizes input before validation to prevent bypassing filters with encoded attacks.
# Failure to canonicalize input is a very common mistake when implementing validation schemes.
# Canonicalization is automatic when using the ESAPI Validator, but you can also use the
# following code to canonicalize data.
#
#      ESAPI.Encoder().canonicalize( "%22hello world&#x22;" );
#  
# Multiple encoding is when a single encoding format is applied multiple times. Allowing
# multiple encoding is strongly discouraged.
Encoder.AllowMultipleEncoding=false

# Mixed encoding is when multiple different encoding formats are applied, or when 
# multiple formats are nested. Allowing multiple encoding is strongly discouraged.
Encoder.AllowMixedEncoding=false

# The default list of codecs to apply when canonicalizing untrusted data. The list should include the codecs
# for all downstream interpreters or decoders. For example, if the data is likely to end up in a URL, HTML, or
# inside JavaScript, then the list of codecs below is appropriate. The order of the list is not terribly important.
Encoder.DefaultCodecList=HTMLEntityCodec,PercentCodec,JavaScriptCodec


#===========================================================================
# ESAPI Encryption
#
# The ESAPI Encryptor provides basic cryptographic functions with a simplified API.
# To get started, generate a new key using java -classpath esapi.jar org.owasp.esapi.reference.crypto.JavaEncryptor
# There is not currently any support for key rotation, so be careful when changing your key and salt as it
# will invalidate all signed, encrypted, and hashed data.
#
# WARNING: Not all combinations of algorithms and key lengths are supported.
# If you choose to use a key length greater than 128, you MUST download the
# unlimited strength policy files and install in the lib directory of your JRE/JDK.
# See http://java.sun.com/javase/downloads/index.jsp for more information.
#
#		***** IMPORTANT: Do NOT forget to replace these with your own values! *****
# To calculate these values, you can run:
#		java -classpath esapi.jar org.owasp.esapi.reference.crypto.JavaEncryptor
#
#Encryptor.MasterKey=
#Encryptor.MasterSalt=

# Provides the default JCE provider that ESAPI will "prefer" for its symmetric
# encryption and hashing. (That is it will look to this provider first, but it
# will defer to other providers if the requested algorithm is not implemented
# by this provider.) If left unset, ESAPI will just use your Java VM's current
# preferred JCE provider, which is generally set in the file
# "$JAVA_HOME/jre/lib/security/java.security".
#
# The main intent of this is to allow ESAPI symmetric encryption to be
# used with a FIPS 140-2 compliant crypto-module. For details, see the section
# "Using ESAPI Symmetric Encryption with FIPS 140-2 Cryptographic Modules" in
# the ESAPI 2.0 Symmetric Encryption User Guide, at:
# http://owasp-esapi-java.googlecode.com/svn/trunk/documentation/esapi4java-core-2.0-symmetric-crypto-user-guide.html
# However, this property also allows you to easily use an alternate JCE provider
# such as "Bouncy Castle" without having to make changes to "java.security".
# See Javadoc for SecurityProviderLoader for further details. If you wish to use
# a provider that is not known to SecurityProviderLoader, you may specify the
# fully-qualified class name of the JCE provider class that implements
# java.security.Provider. If the name contains a '.', this is interpreted as
# a fully-qualified class name that implements java.security.Provider.
#
# NOTE: Setting this property has the side-effect of changing it in your application
#       as well, so if you are using JCE in your application directly rather than
#       through ESAPI (you wouldn't do that, would you? ;-), it will change the
#       preferred JCE provider there as well.
#
# Default: Keeps the JCE provider set to whatever JVM sets it to.
Encryptor.PreferredJCEProvider=

# AES is the most widely used and strongest encryption algorithm. This
# should agree with your Encryptor.CipherTransformation property.
# Warning: This property does not control the default reference implementation for
#		   ESAPI 2.0 using JavaEncryptor. Also, this property will be dropped
#		   in the future.
# @deprecated
Encryptor.EncryptionAlgorithm=AES
#		For ESAPI Java 2.0 - New encrypt / decrypt methods use this.
Encryptor.CipherTransformation=AES/CBC/PKCS5Padding

# Applies to ESAPI 2.0 and later only!
# Comma-separated list of cipher modes that provide *BOTH*
# confidentiality *AND* message authenticity. (NIST refers to such cipher
# modes as "combined modes" so that's what we shall call them.) If any of these
# cipher modes are used then no MAC is calculated and stored
# in the CipherText upon encryption. Likewise, if one of these
# cipher modes is used with decryption, no attempt will be made
# to validate the MAC contained in the CipherText object regardless
# of whether it contains one or not. Since the expectation is that
# these cipher modes support support message authenticity already,
# injecting a MAC in the CipherText object would be at best redundant.
#
# Note that as of JDK 1.5, the SunJCE provider does not support *any*
# of these cipher modes. Of these listed, only GCM and CCM are currently
# NIST approved. YMMV for other JCE providers. E.g., Bouncy Castle supports
# GCM and CCM with "NoPadding" mode, but not with "PKCS5Padding" or other
# padding modes.
Encryptor.cipher_modes.combined_modes=GCM,CCM,IAPM,EAX,OCB,CWC

# Applies to ESAPI 2.0 and later only!
# Additional cipher modes allowed for ESAPI 2.0 encryption. These
# cipher modes are in _addition_ to those specified by the property
# 'Encryptor.cipher_modes.combined_modes'.
# DISCUSS: Better name?
Encryptor.cipher_modes.additional_allowed=CBC

# Default key size to use for cipher specified by Encryptor.EncryptionAlgorithm.
# Note that this MUST be a valid key size for the algorithm being used
# (as specified by Encryptor.EncryptionAlgorithm). So for example, if AES is used,
# it must be 128, 192, or 256. If DESede is chosen, then it must be either 112 or 168.
#
# Note that 128-bits is almost always sufficient and for AES it appears to be more
# somewhat more resistant to related key attacks than is 256-bit AES.)
#
# Defaults to 128-bits if left blank.
#
# NOTE: If you use a key size > 128-bits, then you MUST have the JCE Unlimited
#       Strength Jurisdiction Policy files installed!!!
#
Encryptor.EncryptionKeyLength=128

# This is the _minimum_ key size (in bits) that we allow with ANY symmetric
# cipher for doing encryption. (There is no minimum for decryption.)
#
# Generally, if you only use one algorithm, this should be set the same as
# the Encryptor.EncryptionKeyLength property.
Encryptor.MinEncryptionKeyLength=128

# Because 2.x uses CBC mode by default, it requires an initialization vector (IV).
# (All cipher modes except ECB require an IV.) Previously there were two choices: we can either
# use a fixed IV known to both parties or allow ESAPI to choose a random IV. The
# former was deprecated in ESAPI 2.2 and removed in ESAPI 2.3. It was not secure
# because the Encryptor (as are all the other major ESAPI components) is a
# singleton and thus the same IV would get reused each time. It was not a
# well-thought out plan. (To do it correctly means we need to add a setIV() method
# and get rid of the Encryptor singleton, thus it will not happen until 3.0.)
# However, while the IV does not need to be hidden from adversaries, it is important that the
# adversary not be allowed to choose it. Thus for now, ESAPI just chooses a random IV.
# Originally there was plans to allow a developer to provide a class and method
# name to define a custom static method to generate an IV, but that is just
# trouble waiting to happen. Thus in effect, the ONLY acceptable property value
# for this property is "random". In the not too distant future (possibly the
# next release), I will be removing it, but for now I am leaving this and
# checking for it so a ConfigurationException can be thrown if anyone using
# ESAPI ignored the deprecation warning message and still has it set to "fixed".
#
# Valid values:		random
Encryptor.ChooseIVMethod=random


# Whether or not CipherText should use a message authentication code (MAC) with it.
# This prevents an adversary from altering the IV as well as allowing a more
# fool-proof way of determining the decryption failed because of an incorrect
# key being supplied. This refers to the "separate" MAC calculated and stored
# in CipherText, not part of any MAC that is calculated as a result of a
# "combined mode" cipher mode.
#
# If you are using ESAPI with a FIPS 140-2 cryptographic module, you *must* also
# set this property to false. That is because ESAPI takes the master key and
# derives 2 keys from it--a key for the MAC and a key for encryption--and
# because ESAPI is not itself FIPS 140-2 verified such intermediary aterations
# to keys from FIPS approved sources would have the effect of making your FIPS
# approved key generation and thus your FIPS approved JCE provider unapproved!
# More details in
#       documentation/esapi4java-core-2.0-readme-crypto-changes.html
#       documentation/esapi4java-core-2.0-symmetric-crypto-user-guide.html
# You have been warned.
Encryptor.CipherText.useMAC=true

# Whether or not the PlainText object may be overwritten and then marked
# eligible for garbage collection. If not set, this is still treated as 'true'.
Encryptor.PlainText.overwrite=true

# Do not use DES except in a legacy situations. 56-bit is way too small key size.
#Encryptor.EncryptionKeyLength=56
#Encryptor.MinEncryptionKeyLength=56
#Encryptor.EncryptionAlgorithm=DES

# TripleDES is considered strong enough for most purposes.
#	Note:	There is also a 112-bit version of DESede. Using the 168-bit version
#			requires downloading the special jurisdiction policy from Sun.
#Encryptor.EncryptionKeyLength=168
#Encryptor.MinEncryptionKeyLength=112
#Encryptor.EncryptionAlgorithm=DESede

Encryptor.HashAlgorithm=SHA-512
Encryptor.HashIterations=1024
Encryptor.DigitalSignatureAlgorithm=SHA1withDSA
Encryptor.DigitalSignatureKeyLength=1024
Encryptor.RandomAlgorithm=SHA1PRNG
Encryptor.CharacterEncoding=UTF-8

# This is the Pseudo Random Function (PRF) that ESAPI's Key Derivation Function
# (KDF) normally uses. Note this is *only* the PRF used for ESAPI's KDF and
# *not* what is used for ESAPI's MAC. (Currently, HmacSHA1 is always used for
# the MAC, mostly to keep the overall size at a minimum.)
#
# Currently supported choices for JDK 1.5 and 1.6 are:
#	HmacSHA1 (160 bits), HmacSHA256 (256 bits), HmacSHA384 (384 bits), and
#	HmacSHA512 (512 bits).
# Note that HmacMD5 is *not* supported for the PRF used by the KDF even though
# the JDKs support it.  See the ESAPI 2.0 Symmetric Encryption User Guide
# further details.
Encryptor.KDF.PRF=HmacSHA256
#===========================================================================
# ESAPI HttpUtilties
#
# The HttpUtilities provide basic protections to HTTP requests and responses. Primarily these methods 
# protect against malicious data from attackers, such as unprintable characters, escaped characters,
# and other simple attacks. The HttpUtilities also provides utility methods for dealing with cookies,
# headers, and CSRF tokens.
#
# Default file upload location (remember to escape backslashes with \\)
HttpUtilities.UploadDir=C:\\ESAPI\\testUpload
HttpUtilities.UploadTempDir=C:\\temp
# Force flags on cookies, if you use HttpUtilities to set cookies
HttpUtilities.ForceHttpOnlySession=false
HttpUtilities.ForceSecureSession=false
HttpUtilities.ForceHttpOnlyCookies=true
HttpUtilities.ForceSecureCookies=true
# Maximum size of HTTP header key--the validator regex may have additional values. 
HttpUtilities.MaxHeaderNameSize=256
# Maximum size of HTTP header value--the validator regex may have additional values. 
HttpUtilities.MaxHeaderValueSize=4096
# Maximum size of JSESSIONID for the application--the validator regex may have additional values.  
HttpUtilities.HTTPJSESSIONIDLENGTH=50
# Maximum length of a URL (see https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers)
HttpUtilities.URILENGTH=2000
# Maximum length of a redirect 
HttpUtilities.maxRedirectLength=512
# Maximum length for an http scheme
HttpUtilities.HTTPSCHEMELENGTH=10
# Maximum length for an http host
HttpUtilities.HTTPHOSTLENGTH=100
# Maximum length for an http path
HttpUtilities.HTTPPATHLENGTH=150
#Maximum length for a context path 
HttpUtilities.contextPathLength=150
#Maximum length for an httpServletPath 
HttpUtilities.HTTPSERVLETPATHLENGTH=100
#Maximum length for an http query parameter name
HttpUtilities.httpQueryParamNameLength=100
#Maximum length for an http query parameter -- old default was 2000, but that's the max length for a URL...
HttpUtilities.httpQueryParamValueLength=500
# File upload configuration
HttpUtilities.ApprovedUploadExtensions=.pdf,.doc,.docx,.ppt,.pptx,.xls,.xlsx,.rtf,.txt,.jpg,.png
HttpUtilities.MaxUploadFileBytes=500000000
# Using UTF-8 throughout your stack is highly recommended. That includes your database driver,
# container, and any other technologies you may be using. Failure to do this may expose you
# to Unicode transcoding injection attacks. Use of UTF-8 does not hinder internationalization.
HttpUtilities.ResponseContentType=text/html; charset=UTF-8
# This is the name of the cookie used to represent the HTTP session
# Typically this will be the default "JSESSIONID" 
HttpUtilities.HttpSessionIdName=JSESSIONID
#Sets whether or not we will overwrite http status codes to 200.
HttpUtilities.OverwriteStatusCodes=true
#Sets the application's base character encoding.  This is forked from the Java Encryptor property.
HttpUtilities.CharacterEncoding=UTF-8

#===========================================================================
# ESAPI Executor
# CHECKME - This should be made OS independent. Don't use unsafe defaults.
# # Examples only -- do NOT blindly copy!
#   For Windows:
#     Executor.WorkingDirectory=C:\\Windows\\Temp
#     Executor.ApprovedExecutables=C:\\Windows\\System32\\cmd.exe,C:\\Windows\\System32\\runas.exe
#   For *nux, MacOS:
#     Executor.WorkingDirectory=/tmp
#     Executor.ApprovedExecutables=/bin/bash
Executor.WorkingDirectory=
Executor.ApprovedExecutables=


#===========================================================================
# ESAPI Logging
# Set the application name if these logs are combined with other applications
Logger.ApplicationName=ExampleApplication
# If you use an HTML log viewer that does not properly HTML escape log data, you can set LogEncodingRequired to true
Logger.LogEncodingRequired=false
# Determines whether ESAPI should log the application name. This might be clutter in some single-server/single-app environments.
Logger.LogApplicationName=true
# Determines whether ESAPI should log the server IP and port. This might be clutter in some single-server environments.
Logger.LogServerIP=true
# Determines whether ESAPI should log the user info.
Logger.UserInfo=true
# Determines whether ESAPI should log the session id and client IP.
Logger.ClientInfo=true

#===========================================================================
# ESAPI Intrusion Detection
#
# Each event has a base to which .count, .interval, and .action are added
# The IntrusionException will fire if we receive "count" events within "interval" seconds
# The IntrusionDetector is configurable to take the following actions: log, logout, and disable
#  (multiple actions separated by commas are allowed e.g. event.test.actions=log,disable
#
# Custom Events
# Names must start with "event." as the base
# Use IntrusionDetector.addEvent( "test" ) in your code to trigger "event.test" here
# You can also disable intrusion detection completely by changing
# the following parameter to true
#
IntrusionDetector.Disable=false
#
IntrusionDetector.event.test.count=2
IntrusionDetector.event.test.interval=10
IntrusionDetector.event.test.actions=disable,log

# Exception Events
# All EnterpriseSecurityExceptions are registered automatically
# Call IntrusionDetector.getInstance().addException(e) for Exceptions that do not extend EnterpriseSecurityException
# Use the fully qualified classname of the exception as the base

# any intrusion is an attack
IntrusionDetector.org.owasp.esapi.errors.IntrusionException.count=1
IntrusionDetector.org.owasp.esapi.errors.IntrusionException.interval=1
IntrusionDetector.org.owasp.esapi.errors.IntrusionException.actions=log,disable,logout

# for test purposes
# CHECKME: Shouldn't there be something in the property name itself that designates
#		   that these are for testing???
IntrusionDetector.org.owasp.esapi.errors.IntegrityException.count=10
IntrusionDetector.org.owasp.esapi.errors.IntegrityException.interval=5
IntrusionDetector.org.owasp.esapi.errors.IntegrityException.actions=log,disable,logout

# rapid validation errors indicate scans or attacks in progress
# org.owasp.esapi.errors.ValidationException.count=10
# org.owasp.esapi.errors.ValidationException.interval=10
# org.owasp.esapi.errors.ValidationException.actions=log,logout

# sessions jumping between hosts indicates session hijacking
IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.count=2
IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.interval=10
IntrusionDetector.org.owasp.esapi.errors.AuthenticationHostException.actions=log,logout


#===========================================================================
# ESAPI Validation
#
# The ESAPI Validator works on regular expressions with defined names. You can define names
# either here, or you may define application specific patterns in a separate file defined below.
# This allows enterprises to specify both organizational standards as well as application specific
# validation rules.
#
# Use '\p{L}' (without the quotes) within the character class to match
# any Unicode LETTER. You can also use a range, like:  \u00C0-\u017F
# You can also use any of the regex flags as documented at
# https://docs.oracle.com/javase/tutorial/essential/regex/pattern.html, e.g. (?u)
#
Validator.ConfigurationFile=validation.properties

# Validators used by ESAPI
Validator.AccountName=^[a-zA-Z0-9]{3,20}$
Validator.SystemCommand=^[a-zA-Z\\-\\/]{1,64}$
Validator.RoleName=^[a-z]{1,20}$

#the word TEST below should be changed to your application 
#name - only relative URL's are supported
Validator.Redirect=^\\/test.*$

# Global HTTP Validation Rules
# Values with Base64 encoded data (e.g. encrypted state) will need at least [a-zA-Z0-9\/+=]
Validator.HTTPScheme=^(http|https)$
Validator.HTTPServerName=^[a-zA-Z0-9_.\\-]*$
Validator.HTTPCookieName=^[a-zA-Z0-9\\-_]{1,32}$
Validator.HTTPCookieValue=^[a-zA-Z0-9\\-\\/+=_ ]{0,1024}$
# Note that headerName and Value length is also configured in the HTTPUtilities section
Validator.HTTPHeaderName=^[a-zA-Z0-9\\-_]{1,256}$
Validator.HTTPHeaderValue=^[a-zA-Z0-9()\\-=\\*\\.\\?;,+\\/:&_ ]*$
Validator.HTTPServletPath=^[a-zA-Z0-9.\\-\\/_]*$
Validator.HTTPPath=^[a-zA-Z0-9.\\-_]*$
Validator.HTTPURL=^.*$
Validator.HTTPJSESSIONID=^[A-Z0-9]{10,32}$


# Contributed by Fraenku@gmx.ch
# Github Issue 126 https://github.com/ESAPI/esapi-java-legacy/issues/126
Validator.HTTPParameterName=^[a-zA-Z0-9_\\-]{1,32}$
Validator.HTTPParameterValue=^[-\\p{L}\\p{N}./+=_ !$*?@]{0,1000}$
Validator.HTTPContextPath=^/[a-zA-Z0-9.\\-_]*$
Validator.HTTPQueryString=^([a-zA-Z0-9_\\-]{1,32}=[\\p{L}\\p{N}.\\-/+=_ !$*?@%]*&?)*$
Validator.HTTPURI=^/([a-zA-Z0-9.\\-_]*/?)*$


# Validation of file related input
Validator.FileName=^[a-zA-Z0-9!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1,255}$
Validator.DirectoryName=^[a-zA-Z0-9:/\\\\!@#$%^&{}\\[\\]()_+\\-=,.~'` ]{1,255}$

# Validation of dates. Controls whether or not 'lenient' dates are accepted.
# See DataFormat.setLenient(boolean flag) for further details.
Validator.AcceptLenientDates=false

#                       ~~~~~ Important Note ~~~~~
# This is a workaround to make sure that a commit to address GitHub issue #509
# doesn't accidentally break someone's production code. So essentially what we
# are doing is to reverting back to the previous possibly buggy (by
# documentation intent at least), but, by now, expected legacy behavior.
# Prior to the code changes for issue #509, if invalid / malicious HTML input was
# observed, AntiSamy would simply attempt to sanitize (cleanse) it and it would
# only be logged. However, the code change made ESAPI comply with its
# documentation, which stated that a ValidationException should be thrown in
# such cases. Unfortunately, changing this behavior--especially when no one is
# 100% certain that the documentation was correct--could break existing code
# using ESAPI so after a lot of debate, issue #521 was created to restore the
# previous behavior, but still allow the documented behavior. (We did this
# because it wasn't really causing an security issues since AntiSamy would clean
# it up anyway and we value backward compatibility as long as it doesn't clearly
# present security vulnerabilities.)
# More defaults about this are written up under GitHub issue #521 and
# the pull request it references. Future major releases of ESAPI (e.g., ESAPI 3.x)
# will not support this previous behavior, but it will remain for ESAPI 2.x.
# Set this to 'throw' if you want the originally intended behavior of throwing
# that was fixed via issue #509. Set to 'clean' if you want want the HTML input
# sanitized instead.
#
# Possible values:
#   clean -- Use the legacy behavior where unsafe HTML input is logged and the
#            sanitized (i.e., clean) input as determined by AntiSamy and your
#            AntiSamy rules is returned. This is the default behavior if this
#            new property is not found.
#   throw -- The new, presumably correct and originally intended behavior where
#            a ValidationException is thrown when unsafe HTML input is
#            encountered.
#
#Validator.HtmlValidationAction=clean
Validator.HtmlValidationAction=throw

# With the fix for #310 to enable loading antisamy-esapi.xml from the classpath
# also an enhancement was made to be able to use a different filename for the configuration.
# You don't have to configure the filename here, but in that case the code will keep looking for antisamy-esapi.xml.
# This is the default behaviour of ESAPI.
#
#Validator.HtmlValidationConfigurationFile=antisamy-esapi.xml

esapi-java-logging.properties

handlers= java.util.logging.ConsoleHandler
.level= INFO
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter
java.util.logging.SimpleFormatter.format=[%1$tF %1$tT] [%3$-7s] %5$s %n
#https://www.logicbig.com/tutorials/core-java-tutorial/logging/customizing-default-format.html

validation.properties

# The ESAPI validator does many security checks on input, such as canonicalization
# and whitelist validation. Note that all of these validation rules are applied *after*
# canonicalization. Double-encoded characters (even with different encodings involved,
# are never allowed.
#
# To use:
#
# First set up a pattern below. You can choose any name you want, prefixed by the word
# "Validation." For example:
#   Validation.Email=^[A-Za-z0-9._%-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,4}$
# 
# Then you can validate in your code against the pattern like this:
#     ESAPI.validator().isValidInput("User Email", input, "Email", maxLength, allowNull);
# Where maxLength and allowNull are set for you needs, respectively.
#
# But note, when you use boolean variants of validation functions, you lose critical 
# canonicalization. It is preferable to use the "get" methods (which throw exceptions) and 
# and use the returned user input which is in canonical form. Consider the following:
#  
# try {
#    someObject.setEmail(ESAPI.validator().getValidInput("User Email", input, "Email", maxLength, allowNull));
#
Validator.SafeString=^[.\\p{Alnum}\\p{Space}]{0,1024}$
Validator.Email=^[A-Za-z0-9._%'-]+@[A-Za-z0-9.-]+\\.[a-zA-Z]{2,4}$
Validator.IPAddress=^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$
Validator.URL=^(ht|f)tp(s?)\\:\\/\\/[0-9a-zA-Z]([-.\\w]*[0-9a-zA-Z])*(:(0-9)*)*(\\/?)([a-zA-Z0-9\\-\\.\\?\\,\\:\\'\\/\\\\\\+=&;%\\$#_]*)?$
Validator.CreditCard=^(\\d{4}[- ]?){3}\\d{4}$
Validator.SSN=^(?!000)([0-6]\\d{2}|7([0-6]\\d|7[012]))([ -]?)(?!00)\\d\\d\\3(?!0000)\\d{4}$


antisamy-esapi.xml

<?xml version="1.0" encoding="ISO-8859-1"?>
	
<!-- 
W3C rules retrieved from:
http://www.w3.org/TR/html401/struct/global.html
-->
	
<!--
Slashdot allowed tags taken from "Reply" page:
<b> <i> <p> <br> <a> <ol> <ul> <li> <dl> <dt> <dd> <em> <strong> <tt> <blockquote> <div> <ecode> <quote>
-->

<anti-samy-rules xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
		xsi:noNamespaceSchemaLocation="antisamy.xsd">
	
	<directives>
		<directive name="omitXmlDeclaration" value="true"/>
		<directive name="omitDoctypeDeclaration" value="true"/>
		<directive name="maxInputSize" value="500000"/>
		<directive name="embedStyleSheets" value="false"/>
	</directives>
	
	
	<common-regexps>
		
		<!-- 
		From W3C:
		This attribute assigns a class name or set of class names to an
		element. Any number of elements may be assigned the same class
		name or names. Multiple class names must be separated by white 
		space characters.
		-->
		
		<regexp name="htmlTitle" value="[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&amp;]*"/>
		<regexp name="onsiteURL" value="^(?!//)(?![\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*(&amp;colon))[\p{L}\p{N}\\\.\#@\$%\+&amp;;\-_~,\?=/!]*"/>
		<regexp name="offsiteURL" value="(\s)*((ht|f)tp(s?)://|mailto:)[\p{L}\p{N}]+[\p{L}\p{N}\p{Zs}\.\#@\$%\+&amp;;:\-_~,\?=/!\(\)]*(\s)*"/>
	
	</common-regexps>
	
	<!-- 
	
	Tag.name = a, b, div, body, etc.
	Tag.action = filter: remove tags, but keep content, validate: keep content as long as it passes rules, remove: remove tag and contents
	Attribute.name = id, class, href, align, width, etc.
	Attribute.onInvalid = what to do when the attribute is invalid, e.g., remove the tag (removeTag), remove the attribute (removeAttribute), filter the tag (filterTag)
	Attribute.description = What rules in English you want to tell the users they can have for this attribute. Include helpful things so they'll be able to tune their HTML
	 
	 -->

	<!-- 
	Some attributes are common to all (or most) HTML tags. There aren't many that qualify for this. You have to make sure there's no
	collisions between any of these attribute names with attribute names of other tags that are for different purposes.
	-->

	<common-attributes>
		

		<attribute name="lang" description="The 'lang' attribute tells the browser what language the element's attribute values and content are written in">
		 	<regexp-list>
		 		<regexp value="[a-zA-Z]{2,20}"/>
		 	</regexp-list>
		 </attribute>
		 
		 <attribute name="title" description="The 'title' attribute provides text that shows up in a 'tooltip' when a user hovers their mouse over the element">
		 	<regexp-list>
		 		<regexp name="htmlTitle"/>
		 	</regexp-list>
		 </attribute>

		<attribute name="href" onInvalid="filterTag">
			<regexp-list>
				<regexp name="onsiteURL"/>
				<regexp name="offsiteURL"/>
			</regexp-list>
		</attribute>
	
		<attribute name="align" description="The 'align' attribute of an HTML element is a direction word, like 'left', 'right' or 'center'">
			<literal-list>
				<literal value="center"/>
				<literal value="left"/>
				<literal value="right"/>
				<literal value="justify"/>
				<literal value="char"/>
			</literal-list>
		</attribute>

	</common-attributes>


	<!--
	This requires normal updates as browsers continue to diverge from the W3C and each other. As long as the browser wars continue
	this is going to continue. I'm not sure war is the right word for what's going on. Doesn't somebody have to win a war after 
	a while?
	 -->
	
	<global-tag-attributes>
		<attribute name="title"/>
		<attribute name="lang"/>
	</global-tag-attributes>


	<tag-rules>

		<!-- Tags related to JavaScript -->

		<tag name="script" action="remove"/>
		<tag name="noscript" action="remove"/>
		
		<!-- Frame & related tags -->
		
		<tag name="iframe" action="remove"/>
		<tag name="frameset" action="remove"/>
		<tag name="frame" action="remove"/>
		<tag name="noframes" action="remove"/>
		

		<!-- All reasonable formatting tags -->
		
		<tag name="p" action="validate">
			<attribute name="align"/>
		</tag>

		<tag name="div" action="validate"/>		
		<tag name="i" action="validate"/>
		<tag name="b" action="validate"/>
		<tag name="em" action="validate"/>
		<tag name="blockquote" action="validate"/>
		<tag name="tt" action="validate"/>
		
		<tag name="br" action="truncate"/>

		<!-- Custom Slashdot tags, though we're trimming the idea of having a possible mismatching end tag with the endtag="" attribute -->
		
		<tag name="quote" action="validate"/>
		<tag name="ecode" action="validate"/> 
		
						
		<!-- Anchor and anchor related tags -->
		
		<tag name="a" action="validate">

			<attribute name="href" onInvalid="filterTag"/>
			<attribute name="nohref">
				<literal-list>
					<literal value="nohref"/>
					<literal value=""/>
				</literal-list>
			</attribute>
			<attribute name="rel">
				<literal-list>
					<literal value="nofollow"/>
				</literal-list>
			</attribute>
		</tag>

		<!-- List tags -->

		<tag name="ul" action="validate"/>
		<tag name="ol" action="validate"/>
		<tag name="li" action="validate"/>
		
	</tag-rules>



	<!--  No CSS on Slashdot posts -->

	<css-rules>
	</css-rules>

</anti-samy-rules>

感谢,希望能帮到碰到该问题的你!

依赖下载

见附件

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

薛木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值