一文详解应用安全防护ESAPI
本文分享自华为云社区《应用安全防护ESAPI》,作者: Uncle_Tom。
1. ESAPI 简介
OWASP Enterprise Security API (ESAPI)是一个免费、开源的web应用程序安全控制库,使程序员更容易编写风险较低的应用程序。ESAPI库旨在使程序员更容易对现有应用程序进行安全性改造。ESAPI库也是新开发的坚实基础。
考虑到特定语言的差异,所有OWASP ESAPI版本都有相同的基本设计:
- 有一组安全控制接口。例如,定义了传递给安全控件类型的参数类型。
- 每个安全控制都有一个参考实现。例如:基于字符串的输入验证。例如,Java 的 org.owasp.ESAPI.reference.FileBasedAuthenticator 的 ESAPI,而其他参考实现则是成熟的企业级参考实现,例如,org.oasp.ESAPI.reference.DefaultEncoder 或 org.owasp.ESAPI.reference.DefaultValidator。
- 每个安全控件都有自己的实现(可选)。这些类中可能包含应用程序逻辑,这些逻辑可能由您的组织开发或为您的组织而开发。例如:企业身份验证。
- 为使本项目尽可能易于传播并使更多人能够自由自用,本项目的源代码使用了 BSD 许可证。本项目的文档使用了知识共享署名许可证。你可以随意使用、修改ESAPI,甚至将它包含在商业产品中。
2. ESAPI 框架
OWASP ESAPI 已经实现下面安全控件
- 身份认证
- 访问控制
- 输入验证
- 输出编码/转义
- 密码
- 错误处理和日志
- 通信安全
- HTTP 安全
- 安全配置
ESAPI 框架
ESAPI 覆盖的OWASP Top 10
3. ESAPI 的使用
3.1. ESAPI 在 pom.xml 中的配置
目前最新的版本是: 2.5.3.1, 可以直接在Maven 库中找到。
<!-- https://mvnrepository.com/artifact/org.owasp.esapi/esapi --> <dependency> <groupId>org.owasp.esapi</groupId> <artifactId>esapi</artifactId> <version>2.5.3.1</version> <exclusions> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> </exclusion> </exclusions> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>
3.2. 注入类问题的防护
网络安全问题很大一部分是由于注入类问题造成的。这类问题主要是由于对外部输入使用的过程中转码不当造成的,例如:SQL 注入、命令注入、跨站脚本等等。
Encode(编码器接口)包含了许多解码输入和编码输出的方法,这样处理过的字符对于各种解释器都是安全的。
3.2.1. 防护:XSS 跨站脚本攻击
HTML编码器(encodeForHTML)
@Test void testEncodeForHTML() { String input = "<a href='sdfs'></a> < script > alert('xss'); </ script >"; String encodedString = ESAPI.encoder().encodeForHTML(input); LOG.info("EncodeForHTML: {}", encodedString); }
输出:
EncodeForHTML: <a href='xss'></a> < script > alert('xss'); </ script >
URL编码器(encodeForURL)
@Test void testEncodeForURL() { String input = "/?callback=<script>alert('xss')</script>"; String encodedString; try { encodedString = ESAPI.encoder().encodeForURL(input); LOG.info("EncodeForURL: {}", encodedString); } catch (EncodingException e) { fail("Should not get exception:" + e.getMessage()); } }
输出:
EncodeForURL: %2F%3Fcallback%3D%3Cscript%3Ealert%28%27xss%27%29%3C%2Fscript%3E
3.2.2. 防护:SQL 注入
@Test void testEncodeForSQL() { String userId = "tom' or '1=1'"; String sql = "select * from user where user='" + ESAPI.encoder().encodeForSQL(new MySQLCodec(MySQLCodec.Mode.STANDARD), userId) + "'"; LOG.info("sql = {}", sql); }
输出:
sql = select * from user where user='tom\' or \'1\=1\''
3.2.3. 防护:命令注入
@Test void testEncodeForOS() { String input = "dir & dir /s"; String cmd = ESAPI.encoder().encodeForOS(new WindowsCodec(), input); LOG.info("cmd = {}", cmd); }
输出:
cmd = dir^ ^&^ dir^ ^/s
3.3. 输入校验问题的防护
网络安全最大的威胁是外部输入,所以对外部输入的校验对应用安全起着最大的防护作用。
3.3.1. ESAPI的输入校验
ESAPI有一个输入校验配置: validation.properties 给出了常用的校验。
validation.properties
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}$
校验接口
/** * 输入校验 * * @param context 校验内容 * @param input 校验输入 * @param type 校验类型,对应到 validation.properties 中的类型 * @param maxLength 输入字符最大长度校验 * @param allowNull 输入字符Null值校验,false - 不允许;true - 允许 * @return 校验失败返回 false,校验成功返回 true */ boolean ESAPI.validator().getValidInput(String context, String input, String type, int maxLength, boolean allowNull);
@Test void testValidatorEmail() { String input = "xxxx.com"; if (!ESAPI.validator().isValidInput("", input, "Email", 11, false)) { LOG.error("Email validate fail!"); } else { LOG.info("Email is validate."); } }
输出:
Email validate fail!
4. ESAPI 使用和升级过程中常遇到的问题
4.1. ExceptionInInitializerError 造成的 org.owasp.esapi.reference.DefaultEncoder CTOR threw exception
org.owasp.esapi.errors.ConfigurationException: java.lang.reflect.InvocationTargetException Encoder class (org.owasp.esapi.reference.DefaultEncoder) CTOR threw exception. at org.owasp.esapi.util.ObjFactory.make(ObjFactory.java:129) at org.owasp.esapi.ESAPI.encoder(ESAPI.java:101) at com.test.esapi.EsapiTest.testUpdateJulietInfo_good(EsapiTest.java:19) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Caused by: java.lang.reflect.InvocationTargetException at org.owasp.esapi.util.ObjFactory.make(ObjFactory.java:86) ... 71 more Caused by: java.lang.ExceptionInInitializerError at java.base/java.lang.Class.forName0(Native Method) at java.base/java.lang.Class.forName(Class.java:375) at org.owasp.esapi.util.ObjFactory.loadClassByStringName(ObjFactory.java:158) at org.owasp.esapi.util.ObjFactory.make(ObjFactory.java:81) at org.owasp.esapi.ESAPI.logFactory(ESAPI.java:139) at org.owasp.esapi.ESAPI.getLogger(ESAPI.java:155) at org.owasp.esapi.reference.DefaultEncoder.(DefaultEncoder.java:85) at org.owasp.esapi.reference.DefaultEncoder.(DefaultEncoder.java:109) at org.owasp.esapi.reference.DefaultEncoder.getInstance(DefaultEncoder.java:68) ... 76 more Caused by: org.owasp.esapi.errors.ConfigurationException: Unable to locate resource: esapi-java-logging.properties at org.owasp.esapi.logging.java.JavaLogFactory.readLoggerConfiguration(JavaLogFactory.java:128) at org.owasp.esapi.logging.java.JavaLogFactory.(JavaLogFactory.java:96) ... 85 more
这个是 ESAPI 升级到 2.5.0.0 之后的版本时,最常碰到的问题。
2.5.0.0 是 ESAPI 一个重要的变动版本,我们从版本变更信息中可以看到:
- 此版本 ESAPI 全面放弃了被 Log4J 不断的漏洞困扰的 Log4J 的支持,转而使用 SLF4J。如果您的 ESAPI.Logger 属性设置为使用 Log4J,如果不更改它,将引发模糊的 Exceptions 或 Errors,通常为 ExceptionInInitializerError。
- 对 AntiSamy 升级到了 1.7.0,并支持了 AntiSamy 自定义的 AntiSamy-sapi.xml 文件。
- 从上一个版本开始,此版本仅支持 Java 8 或更高版本。
从这里可以看到 ExceptionInInitializerError 应该是变更日志组件造成的,熟悉的朋友会立刻想到 ESAPI 的配置文件 ESAPI.properties 里面给出所有组件的配置。
从图中 69 到 72 行可以看到,69 行的:
ESAPI.Logger=org.owasp.esapi.logging.java.JavaLogFactory
还是指向 org.owasp.esapi.logging.java.JavaLogFactory, 后面的注释也提醒我们需要修改成 71 行的:
ESAPI.Logger=org.owasp.esapi.logging.slf4j.Slf4JLogFactory
修改后问题解决。
4.2. java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest
java.lang.NoClassDefFoundError: javax/servlet/http/HttpServletRequest at java.base/java.lang.Class.getDeclaredMethods0(Native Method) at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3402) at java.base/java.lang.Class.getMethodsRecursive(Class.java:3543) at java.base/java.lang.Class.getMethod0(Class.java:3529) at java.base/java.lang.Class.getMethod(Class.java:2225) at org.owasp.esapi.util.ObjFactory.loadMethodByStringName(ObjFactory.java:196) at org.owasp.esapi.util.ObjFactory.findSingletonCreateMethod(ObjFactory.java:173) at org.owasp.esapi.util.ObjFactory.make(ObjFactory.java:84) at org.owasp.esapi.ESAPI.validator(ESAPI.java:192) at com.huawei.hwe.esapi.EsapiTest.testEsapi_encodeForURL(EsapiTest.java:23) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) at java.base/java.util.ArrayList.forEach(ArrayList.java:1511) Caused by: java.lang.ClassNotFoundException: javax.servlet.http.HttpServletRequest at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188) at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:525) ... 79 more
这个问题明显是缺少了依赖库。我们可以查看 Maven 库关于 ESAPI 的定义和依赖信息。
https://mvnrepository.com/artifact/org.owasp.esapi/esapi/2.5.3.1
编译依赖
运行依赖
从运行依赖可以看到需要:javax.servlet » javax.servlet-api
点开后面的版本号:3.1.0,就可以得到 javax.servlet-api 3.1.0 的 mvn 依赖配置,将这个配置加到工程的 pom.xml 文件中就可以了。
在 pom.xml 中加入 javax.servlet-api 配置后,问题解决。
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> <scope>provided</scope> </dependency>

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
云小课|Runc容器逃逸漏洞(CVE-2024-21626)安全风险通告
阅识风云是华为云信息大咖,擅长将复杂信息多元化呈现,其出品的一张图(云图说)、深入浅出的博文(云小课)或短视频(云视厅)总有一款能让您快速上手华为云。更多精彩内容请单击此处。 runc官方发布安全公告,披露runc 1.1.11及更早版本中存在容器逃逸漏洞,攻击者会利用该漏洞导致容器逃逸,进一步获取宿主机权限。 本文分享自华为云社区《云小课|Runc容器逃逸漏洞(CVE-2024-21626)安全风险通告》,作者:阅识风云。 近日,华为云主机安全服务团队关注到runc官方发布安全公告,披露runc 1.1.11及更早版本中存在容器逃逸漏洞,攻击者会利用该漏洞导致容器逃逸,进一步获取宿主机权限。 runc官方公告详情参考:https://github.com/opencontainers/runc/security/advisories/GHSA-xr7r-f8xq-vfvv runc官方已发布安全更新修复该漏洞,建议用户及时进行安全自检并做好安全加固以降低被攻击的风险。 一、漏洞情况分析 1. 什么是runc? runc是一个根据OCI(Open Container Initiati...
- 下一篇
财务数据处理问题及解决方案分享
一、平台介绍 财务自营计费主要承接京东自营数据在整个供应链中由C端转B端的功能实现,在整个供应链中属于靠后的阶段了,系统主要功能是计费和向B端的汇总。 二、问题描述 近年来自营计费数据量大增,有百亿+的数据量,一天中汇总占据了一半的数据库资源。 1、每天从单表千万W+中定位几万数据执行汇总,即全库全表执行group by操作,32库*32表,每天要花12小时处理。 2、汇总期间,系统基本停滞,导致了消息、任务处理慢,积压多,数据无法及时计费。 3、数据库压力大,有随时崩溃的风险。 4、影响供应商体验,大促期间供应商要实时查看销售数据,出战报,系统无法及时响应。 三、原技术介绍 系统汇总核心是依靠MySQL物理机在每库每表通过group by进行,汇总是按费用类型分而治之,每种类型汇总维度不一样,每次如有新的汇总维度引入,需从前到后,写一遍新的汇总逻辑,主要是锁定新维度的数据范围,确定新的group by 字段,之前逻辑还得回归测试,很蠢是吧,我也觉得。 四、解决问题的思路和办法 根据以上的背景和问题,确定大致的解决问题思路 1、首先要脱离MySQL汇总,数据库是很脆弱的,要保护数据库,...
相关文章
文章评论
共有0条评论来说两句吧...