Java 安全指南

您所在的位置:网站首页 移动电话号码隐藏 Java 安全指南

Java 安全指南

2024-07-13 08:36| 来源: 网络整理| 查看: 265

Java 安全指南 后台类

I. 代码实现

1.1 数据持久化 1.1.1【必须】SQL语句默认使用预编译并绑定变量

Web后台系统应默认使用预编译绑定变量的形式创建sql语句,保持查询语句和数据相分离。以从本质上避免SQL注入风险。

如使用Mybatis作为持久层框架,应通过#{}语法进行参数绑定,MyBatis 会创建 PreparedStatement 参数占位符,并通过占位符安全地设置参数。

示例:JDBC

String custname = request.getParameter("name"); String query = "SELECT * FROM user_data WHERE user_name = ? "; PreparedStatement pstmt = connection.prepareStatement( query ); pstmt.setString( 1, custname); ResultSet results = pstmt.executeQuery( );

Mybatis

select rule_id from scan_rule_sqlmap_tab where application_id=#{applicationId}

应避免外部输入未经过滤直接拼接到SQL语句中,或者通过Mybatis中的${}传入SQL语句(即使使用PreparedStatement,SQL语句直接拼接外部输入也同样有风险。例如Mybatis中部分参数通过${}传入SQL语句后实际执行时调用的是PreparedStatement.execute(),同样存在注入风险)。

1.1.2【必须】白名单过滤

对于表名、列名等无法进行预编译的场景,比如外部数据拼接到order by, group by语句中,需通过白名单的形式对数据进行校验,例如判断传入列名是否存在、升降序仅允许输入“ASC”和“DESC”、表明列名仅允许输入字符、数字、下划线等。参考示例:

public String someMethod(boolean sortOrder) { String SQLquery = "some SQL ... order by Salary " + (sortOrder ? "ASC" : "DESC");` ...

1.2 文件操作 1.2.1【必须】文件类型限制

须在服务器端采用白名单方式对上传或下载的文件类型、大小进行严格的限制。仅允许业务所需文件类型上传,避免上传.jsp、.jspx、.class、.java等可执行文件。参考示例:

String file_name = file.getOriginalFilename(); String[] parts = file_name.split("\\."); String suffix = parts[parts.length - 1]; switch (suffix){ case "jpeg": suffix = ".jpeg"; break; case "jpg": suffix = ".jpg"; break; case "bmp": suffix = ".bmp"; break; case "png": suffix = ".png"; break; default: //handle error return "error"; } 1.2.2【必须】禁止外部文件存储于可执行目录

禁止外部文件存储于WEB容器的可执行目录(appBase)。建议保存在专门的文件服务器中。

1.2.3【建议】避免路径拼接

文件目录避免外部参数拼接。保存文件目录建议后台写死并对文件名进行校验(字符类型、长度)。建议文件保存时,将文件名替换为随机字符串。

1.2.4【必须】避免路径穿越

如因业务需要不能满足1.2.3的要求,文件路径、文件命中拼接了不可行数据,需判断请求文件名和文件路径参数中是否存在../或..\(仅windows), 如存在应判定路径非法并拒绝请求。

1.3 网络访问 1.3.1【必须】避免直接访问不可信地址

服务器访问不可信地址时,禁止访问私有地址段及内网域名。

// 以RFC定义的专有网络为例,如有自定义私有网段亦应加入禁止访问列表。 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 127.0.0.0/8

建议通过URL解析函数进行解析,获取host或者domain后通过DNS获取其IP,然后和内网地址进行比较。

对已校验通过地址进行访问时,应关闭跟进跳转功能。

参考示例:

httpConnection = (HttpURLConnection) Url.openConnection(); httpConnection.setFollowRedirects(false);

1.4 XML读写 1.4.1【必须】XML解析器关闭DTD解析

读取外部传入XML文件时,XML解析器初始化过程中设置关闭DTD解析。

参考示例:

javax.xml.parsers.DocumentBuilderFactory

DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); try { dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); dbf.setFeature("http://xml.org/sax/features/external-general-entities", false); dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false); dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); dbf.setXIncludeAware(false); dbf.setExpandEntityReferences(false); …… }

org.dom4j.io.SAXReader

saxReader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); saxReader.setFeature("http://xml.org/sax/features/external-general-entities", false); saxReader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

org.jdom2.input.SAXBuilder

SAXBuilder builder = new SAXBuilder(); builder.setFeature("http://apache.org/xml/features/disallow-doctype-decl",true); builder.setFeature("http://xml.org/sax/features/external-general-entities", false); builder.setFeature("http://xml.org/sax/features/external-parameter-entities", false); Document doc = builder.build(new File(fileName));

org.xml.sax.XMLReader

XMLReader reader = XMLReaderFactory.createXMLReader(); reader.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true); reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); reader.setFeature("http://xml.org/sax/features/external-general-entities", false); reader.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

1.5 响应输出 1.5.1【必须】设置正确的HTTP响应包类型

响应包的HTTP头“Content-Type”必须正确配置响应包的类型,禁止非HTML类型的响应包设置为“text/html”。此举会使浏览器在直接访问链接时,将非HTML格式的返回报文当做HTML解析,增加反射型XSS的触发几率。

1.5.2【建议】设置安全的HTTP响应头

X-Content-Type-Options:

建议添加“X-Content-Type-Options”响应头并将其值设置为“nosniff”,可避免部分浏览器根据其“Content-Sniff”特性,将一些非“text/html”类型的响应作为HTML解析,增加反射型XSS的触发几率。

HttpOnly:

控制用户登录鉴权的Cookie字段 应当设置HttpOnly属性以防止被XSS漏洞/JavaScript操纵泄漏。

X-Frame-Options:

设置X-Frame-Options响应头,并根据需求合理设置其允许范围。该头用于指示浏览器禁止当前页面在frame、iframe、embed等标签中展现。从而避免点击劫持问题。它有三个可选的值: DENY: 浏览器会拒绝当前页面加载任何frame页面; SAMEORIGIN:则frame页面的地址只能为同源域名下的页面 ALLOW-FROM origin:可以定义允许frame加载的页面地址。

Access-Control-Allow-Origin

当需要配置CORS跨域时,应对请求头的Origin值做严格过滤。

... String currentOrigin = request.getHeader("Origin"); if (currentOrigin.equals("https://domain.qq.com")) { response.setHeader("Access-Control-Allow-Origin", currentOrigin); } ... 1.5.3【必须】外部输入拼接到response页面前进行编码处理

当响应“content-type”为“html”类型时,外部输入拼接到响应包中,需根据输出位置进行编码处理。编码规则:

场景 编码规则 输出点在HTML标签之间 需要对以下6个特殊字符进行HTML实体编码(&, , ", ',/)。示例:& --> ;< --> ;>--> ;" --> ;' --> ' / --> / 输出点在HTML标签普通属性内(如href、src、style等,on事件除外) 要对数据进行HTML属性编码。编码规则:除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为&#xHH;(以&#x开头,HH则是指该字符对应的十六进制数字,分号作为结束符) 输出点在JS内的数据中 需要进行js编码编码规则:除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \xHH (以 \x 开头,HH则是指该字符对应的十六进制数字)Tips:这种场景仅限于外部数据拼接在js里被引号括起来的变量值中。除此之外禁止直接将代码拼接在js代码中。 输出点在CSS中(Style属性) 需要进行CSS编码编码规则:除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \HH (以 \ 开头,HH则是指该字符对应的十六进制数字) 输出点在URL属性中 对这些数据进行URL编码Tips:除此之外,所有链接类属性应该校验其协议。禁止JavaScript、data和Vb伪协议。

以上编码规则相对较为繁琐,可参考或直接使用业界已有成熟第三方库如ESAPI.其提供一下函数对象上表中的编码规则:

ESAPI.encoder().encodeForHTML(); ESAPI.encoder().encodeForHTMLAttribute(); ESAPI.encoder().encodeForJavaScript(); ESAPI.encoder().encodeForCSS(); ESAPI.encoder().encodeForURL(); 1.5.4【必须】外部输入拼接到HTTP响应头中需进行过滤

应尽量避免外部可控参数拼接到HTTP响应头中,如业务需要则需要过滤掉“\r”、"\n"等换行符,或者拒绝携带换行符号的外部输入。

1.5.5【必须】避免不可信域名的302跳转

如果对外部传入域名进行302跳转,必须设置可信域名列表并对传入域名进行校验。

为避免校验被绕过,应避免直接对URL进行字符串匹配。应通过通过URL解析函数进行解析,获取host或者domain后和白名单进行比较。

需要注意的是,由于浏览器的容错机制,域名https://www.qq.com\www.bbb.com中的\会被替换成/,最终跳转到www.qq.com。而Java的域名解析函数则无此特性。为避免解析不一致导致绕过,建议对host中的/和#进行替换。

参考代码:

String host=""; try { url = url.replaceAll("[\\\\#]","/"); //替换掉反斜线和井号 host = new URL(url).getHost(); } catch (MalformedURLException e) { e.printStackTrace(); } if (host.endsWith(".qq.com")){ //跳转操作 }else{ return; } 1.5.6【必须】避免通过Jsonp传输非公开敏感信息

jsonp请求再被CSRF攻击时,其响应包可被攻击方劫持导致信息泄露。应避免通过jsonp传输非公开的敏感信息,例如用户隐私信息、身份凭证等。

1.5.7【必须】限定JSONP接口的callback字符集范围

JSONP接口的callback函数名为固定白名单。如callback函数名可用户自定义,应限制函数名仅包含 字母、数字和下划线。如:[a-zA-Z0-9_-]+

1.5.8【必须】屏蔽异常栈

应用程序出现异常时,禁止将数据库版本、数据库结构、操作系统版本、堆栈跟踪、文件名和路径信息、SQL 查询字符串等对攻击者有用的信息返回给客户端。建议重定向到一个统一、默认的错误提示页面,进行信息过滤。

1.5.9【必须】模板&表达式

web view层通常通过模板技术或者表达式引擎来实现界面与业务数据分离,比如jsp中的EL表达式。这些引擎通常可执行敏感操作,如果外部不可信数据未经过滤拼接到表达式中进行解析。则可能造成严重漏洞。

下列是基于EL表达式注入漏洞的演示demo:

@RequestMapping("/ELdemo") @ResponseBody public String ELdemo(RepeatDTO repeat) { ExpressionFactory expressionFactory = new ExpressionFactoryImpl(); SimpleContext simpleContext = new SimpleContext(); String exp = "${"+repeat.getel()+"}"; ValueExpression valueExpression = expressionFactory.createValueExpression(simpleContext, exp, String.class); return valueExpression.getValue(simpleContext).toString(); }

外部可通过el参数,将不可信输入拼接到EL表达式中并解析。

此时外部访问:x.x.x.x/ELdemo?el=”''.getClass().forName('java.lang.Runtime').getMethod('exec',''.getClass()).invoke(''.getClass().forName('java.lang.Runtime').getMethod('getRuntime').invoke(null),'open /Applications/Calculator.app')“ 可执行操作系统命令调出计算器。

基于以上风险:

应避免外部输入的内容拼接到EL表达式或其他表达式引起、模板引擎进行解析。 白名单过滤外部输入,仅允许字符、数字、下划线等。

1.6 OS命令执行 1.6.1【建议】避免不可信数据拼接操作系统命令

当不可信数据存在时,应尽量避免外部数据拼接到操作系统命令使用 Runtime 和 ProcessBuilder 来执行。优先使用其他同类操作进行代替,比如通过文件系统API进行文件操作而非直接调用操作系统命令。

1.6.2【必须】避免创建SHELL操作

如无法避免直接访问操作系统命令,需要严格管理外部传入参数,使不可信数据仅作为执行命令的参数而非命令。

禁止外部数据直接直接作为操作系统命令执行。

避免通过"cmd"、“bash”、“sh”等命令创建shell后拼接外部数据来执行操作系统命令。

对外部传入数据进行过滤。可通过白名单限制字符类型,仅允许字符、数字、下划线;或过滤转义以下符号:|;&$>



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3