WEB安全编程技术规范V10.docx
《WEB安全编程技术规范V10.docx》由会员分享,可在线阅读,更多相关《WEB安全编程技术规范V10.docx(36页珍藏版)》请在冰豆网上搜索。
![WEB安全编程技术规范V10.docx](https://file1.bdocx.com/fileroot1/2023-5/23/981dbb3a-edb4-4745-87e7-cb4ff386857f/981dbb3a-edb4-4745-87e7-cb4ff386857f1.gif)
WEB安全编程技术规范V10
1.范围
本规范从应用开发安全管理要求出发,给出了WEB编码安全的具体要求。
供浙江公司IT系统内部和厂商使用,适用于省市公司IT系统项目建设WEB工作。
本规范明确定义了JAVA、PHP应用开发中和WEB编码安全相关的技术细节。
与JAVA编码安全相关的内容包括:
跨站脚本攻击及解决方法、SQL注入及解决方法、恶意文件执行及解决方法、不安全的直接对象引用及解决方法、跨站请求伪造及解决方法、信息泄露和错误处理不当及解决方法、残缺的认证和会话管理及解决方法、不安全的加密存储及解决方法、不安全的通信及解决方法、限制URL访问实效解决方法。
与PHP编码安全相关的内容包括:
变量滥用及解决方法、文件打开漏洞及解决方法、文件包含漏洞及解决方法、文件上传漏洞及解决方法、命令执行漏洞及解决方法、变量类型缺陷及解决方法、警告及错误信息处理解决方法、PHP与MYSQL组合的SQL注入解决方法、跨站脚本解决方法。
2.1.规范概述
Web应用程序为结构设计人员、设计人员和开发人员提出一系列复杂的安全问题。
最安全、最有能力抵御攻击的Web应用程序是那些应用安全思想构建的应用程序。
在设计初始阶段,应该使用可靠的体系结构和设计方法,同时要结合考虑程序部署以及企业的安全策略。
如果不能做到这一点,将导致在现有基础结构上部署应用程序时,要不可避免地危及安全性。
本规范提供一系列安全的体系结构和设计指南,并按照常见的应用程序漏洞类别进行组织。
这些指南是Web应用程序安全的重要方面,并且是经常发生错误的领域。
2.实现目标
使用本规范可以实现:
1.确定安全Web应用程序的重要体系结构和设计问题。
2.设计时考虑重要部署问题。
3.制定能增强Web应用程序输入验证的策略。
4.设计安全的身份验证和会话管理机制。
5.选择适当的授权模型。
6.实现有效的帐户管理方法,并保护用户会话。
7.对隐私、认可、防止篡改和身份验证信息进行加密。
8.防止参数操作。
9.设计审核和记录策略。
3.安全编码原则
1.程序只实现你指定的功能
2.永不要信任用户输入,对用户输入数据做有效性检查
3.必须考虑意外情况并进行处理
4.不要试图在发现错误之后继续执行
5.尽可能使用安全函数进行编程
6.小心、认真、细致地编程
4.安全背景知识
本规范主要提供设计应用程序时应该遵循的一些指南和原则。
为充分理解本规范内容,请:
了解应用程序将会受到的威胁,以确保通过程序设计解决这些问题。
解需要考虑的威胁。
在程序设计阶段应该考虑到这些威胁。
在应用程序易受攻击的重要环节应用系统的方法。
将重点放在程序部署、输入验证、身份验证和授权、加密及数据敏感度、配置、会话、异常管理以及适当的审核和记录策略上,以确保应用程序具有责任性。
5.JAVA安全编程——OWASPTOP10ANDESAPI
5.1OWASPTOP10与ESAPI
OWASP(开放Web应用安全项目-OpenWebApplicationSecurityProject)是一个开放社群、非营利性组织,目前全球有82个分会近万名会员,其主要目是研议协助解决Web软体安全之准、工具与技术文件,长期致力于协助政府或企业解并改善网页应用程式与网页服务的安全性。
OWASPTOP10是10个最关键的Web应用安全问题清单。
这份名单是每隔数年更新(最近2010年)。
名单上都是那些通常很简单的,危险的安全问题。
这里是一个以在OWASP十大项目的链接。
:
//.owasp.org/index.php/Category:
OWASP_Top_Ten_Project
其实简单一点来说,ESAPI就是为编写出更加安全的代码设计出来的一些API,方便使用者调用,从而方便的编写安全的代码。
它本身是开源的,同时提供JAVA版本和.NET版本。
代码下载地址:
:
//
下图显示提供的API与OWASP列出的10个安全问题的盖关系:
下图显示结合ESAPI设计你的程序:
下图简单呈现ESAPI如何运作:
5.2跨站脚本(XSS)
5.2.1定义
跨站脚本是最普遍的web应用安全漏洞。
当应用程序在发送给浏览器的页面中包含用户提供的数据,但没有经过适当验证或转译那些内容,这就导致跨站脚本漏洞。
5.2.2危害
攻击者能在受害者浏览器中执行脚本以劫持用户会话、迫害网站、插入恶意内容、重定向用户、使用恶意软件劫持用户浏览器等等。
5.2.3种类
已知有三种著名跨站漏洞:
1)存储式;2)反射式;3)基于DOM。
反射式跨站脚本通过测试或代码分析很容易找到。
5.2.4解决方法
5.2.4.1.验证输入
验证输入很简单-检查每个输入的有效性。
这可能意味着很多东西,但在典型的和简单的情况下,这意味着检查输入类型和数据的长度。
例如,如果你是从一个文本框接受一个准的邮政编码,你会知道,唯一有效的类型是一个数字(0-9),而长度应该是6,不能多也不能少。
并非所有的案件都如此简单,但很多是相似的。
下图显示验证输入的架构。
这里的关键是,一切都进行验证,所有的输入,这并不来自于应用程序(包括用户输入,请求头,Cookie,数据库数据...)。
◆实例
getValidInput(java.lang.Stringcontext,java.lang.Stringinput,
java.lang.Stringtype,intmaxLength,booleanallowNull,ValidationErrorList
errors)
isValidInput(java.lang.Stringcontext,java.lang.Stringinput,
java.lang.Stringtype,intmaxLength,booleanallowNull)
StringvalidatedFirstName=ESAPI.validator().getValidInput("FirstName",
myForm.getFirstName(),"FirstNameRegex",255,false,errorList);
booleanisValidFirstName=ESAPI.validator().isValidInput("FirstName",
myForm.getFirstName(),"FirstNameRegex",255,false);
5.2.4.2.编码输出
对验证输入的另一面就是编码输出。
编码输出,是用来确保字符被视为数据,而不是作为HTML元字符被浏览器解析。
这些技术定义一些特殊的"转义"字符。
没有正确转义的数据它仍然会在浏览器中正确解析。
编码输出只是让浏览器知道数据是不是要被解析,达到攻击无法实现的目的。
需要编码的部分:
1、HTML实体
2、HTML属性
3、Javascript
4、CSS
5、URL
下图像显示编码输出的架构。
◆实例1——HTML实体编码
//performinginputvalidationStringcleanComment=
ESAPI.validator().getValidInput("comment",
request.getParameter("comment"),"CommentRegex",300,false,errorList);
//checktheerrorListhere......//performingoutputencodingfortheHTML
contextStringsafeOutput=
ESAPI.encoder().encodeForHTML(cleanComment);
◆实例2——URL编码
//performinginputvalidationStringcleanUserName=
ESAPI.validator().getValidInput("userName",
request.getParameter("userName"),"userNameRegex",50,false,errorList);
//checktheerrorListhere......//performingoutputencodingfortheurlcontext
StringsafeOutput="/admin/findUser.do?
name="+
ESAPI.encoder().encodeForURL(cleanUserName);
5.3SQL注入
5.3.1定义
简单来说,注入往往是应用程序缺少对输入进行安全性检查所引起的,攻击者把一些包含指令的数据发送给解释器,解释器会把收到的数据转换成指令执行,注入漏洞十分普遍,通常能在SQL查询、LDAP查询、Xpath查询、OS命令、程序参数等中出现。
5.3.2危害
注入能导致数据丢失或数据破坏、缺乏可审计性或是拒绝服务。
注入漏洞有时甚至能导致完全接管主机。
5.3.3种类
SQL注入、XPATH注入、LDAP注入、OS命令注入等。
5.3.4解决方法
5.3.4.1.SQL注入实例
StringsqlString="SELECT*FROMusersWHEREfullname='"+
form.getFullName()+"'ANDpassword='"+form.getPassword()+"'";
正常:
username=tony,password=123456
SELECT*FROMusersWHEREusername=tony'ANDpassword='123456'
攻击:
username=tony,password='OR'1'='1
SELECT*FROMusersWHEREusername=tony'ANDpassword=''OR'1'='1'
5.3.4.2.参数化查询预处理
使用PreparedStatement()绑定变量
下面的代码示例使用一个PreparedStatement,Java的一个参数化查询的执行情况,执行相同的数据库查询。
Stringcustname=request.getParameter("customerName");//This
shouldREALLYbevalidatedtoo//performinputvalidationtodetectattacks
Stringquery="SELECTaccount_balanceFROMuser_data
WHEREuser_name=?
";
PreparedStatementpstmt=
connection.prepareStatement(query);pstmt.setString(1,custname);
ResultSetresults=pstmt.executeQuery();
5.3.4.3.使用存储过程
Stringcustname=request.getParameter("customerName");
//ThisshouldREALLYbevalidated
try{
CallableStatementcs=connection.prepareCall("{call
sp_getAccountBalance(?
)}");
cs.setString(1,custname);
ResultSetresults=cs.executeQuery();
//⋯resultsethandling
}catch(SQLExceptionse){
//⋯logginganderrorhandling
}
5.3.4.4.使用ESAPI
//ESAPIversionofquery
CodecORACLE_CODEC=newOracleCodec();
//we'reusingoracle
Stringquery="SELECTnameFROMusersWHEREid="+
ESAPI.encoder().encodeForSQL(ORACLE_CODEC,validatedUserId)+"
ANDdate_created>='"+
ESAPI.encoder().encodeForSQL(ORACLE_CODEC,validatedStartDate)+"'";
myStmt=conn.createStatement(query);
...
//executestatementandgetresults
5.4恶意文件执行
5.4.1定义
恶意文件执行是一种能够威胁任何网站形式的漏洞,只要攻击者在具有引入(include)功能程式的参数中修改参数内容,WEB服务器便会引入恶意程序内容从而受到恶意文件执行漏洞攻击。
5.4.2危害
攻击者可利用恶意文件执行漏洞进行攻击取得WEB服务器控制权,进行不法利益或获取经济利益。
5.4.3解决方法
5.4.3.1实例1
验证输入,使用ESAPI验证上传文件名
if(!
ESAPI.validator().isValidFileName("upload",filename,
allowedExtensions,false)){
thrownewValidationUploadException("Uploadonlysimplefilenameswith
thefollowingextensions"+allowedExtensions,"Uploadfailed
isValidFileNamecheck");
}
5.4.3.2实例2
使用ESAPI检查上传文件大小
ServletFileUploadupload=newServletFileUpload(factory);
upload.setSizeMax(maxBytes);
5.5不安全的直接对象引用
5.5.1定义
所谓"不安全的对象直接引用",即Insecuredirectobjectreferences,意指一个已经授权的用户,通过更改访问时的一个参数,从而访问到原本其并没有得到授权的对象。
Web应用往往在生成Web页面时会用它的真实名字,且并不会对所有的目对象访问时来检查用户权限,所以这就造成不安全的对象直接引用的漏洞。
我们看如下的一个示例,也许这样就更容易理解什么是不安全的对象直接引用。
Ø攻击者发现他自己的参数是6065,即?
acct=6065;
Ø他可以直接更改参数为6066,即?
acct=6066;
Ø这样他就可以直接看到6066用户的账户信息。
5.5.2危害
这种漏洞能损害参数所引用的所有数据。
除非名字空间很稀疏,否则攻击者很容易访问该类型的所有数据。
5.5.3解决方法
5.5.3.1.案例1
使用ESAPI的AccessReferenceMap实现使用非直接的对象引用
MyObjectobj;//generateyourobject
Collectioncoll;//holdsobjectsfordisplayinUI
//createESAPIrandomaccessreferencemap
AccessReferenceMapmap=newRandomAccessReferenceMap();
//getindirectreferenceusingdirectreferenceasseedinput
StringindirectReference=map.addDirectReference(obj.getId());
//setindirectreferenceforeachobject-requiresyourappobjecttohavethismethod
bj.setIndirectReference(indirectReference);
//addobjecttodisplaycollection
coll.add(obj);
//storecollectioninrequest/sessionandforwardtoUI
...
5.5.3.2.案例2
检查访问。
来自不受信源所使用的所有直接对象引用都必须包含访问控制检测,这样才能确保用户对要求的对象有访问权限
5.6跨站请求伪造
5.6.1.定义
跨站请求伪造,也被称成为"oneclickattack"或者sessionriding,通常缩写为CSRF或者XSRF,是一种对网站的恶意利用。
尽管听起来像跨站脚本(XSS),但它与XSS非常不同,并且攻击方式几乎相左。
XSS利用站点内的信任用户,而CSRF则通过伪装来自受信任用户的请求来利用受信任的网站。
与XSS攻击相比,CSRF攻击往往不大流行(因此对其进行防范的资源也相当稀少)和难以防范,所以被认为比XSS更具危险性。
5.6.2.危害
攻击者能让受害用户修改可以修改的任何数据,或者是执行允许使用的任何功能。
5.6.3.解决方法
第一步,新建CSRF令牌添加进用户每次登陆以及存储在session里,这种令牌至少对每个用户会话来说应该是唯一的,或者是对每个请求是唯一的。
//thiscodeisintheDefaultUserimplementationofESAPI
/**Thisuser'sCSRFtoken.*/
PrivateStringcsrfToken=resetCSRFToken();
...
PublicStringresetCSRFToken(){
csrfToken=ESAPI.randomizer().getRandomString(8,
DefaultEncoder.CHAR_ALPHANUMERICS);
returncsrfToken;
}
第二步,令牌同样可以包含在URL中或作为一个URL参数记/隐藏字段。
//fromUtilitilesinterface
FinalstaticStringCSRF_TOKEN_NAME="ctoken";
//thiscodeisfromtheDefaultUtilitiesimplementationinESAPI
PublicStringaddCSRFToken(Stringhref){
Useruser=ESAPI.authenticator().getCurrentUser();
if(user.isAnonymous()){returnhref;}
//iftherearealreadyparametersappendwith&,otherwiseappendwith?
Stringtoken=CSRF_TOKEN_NAME+"="+
user.getCSRFToken();
returnhref.indexOf('?
')!
=-1?
href+"&"+token:
href+"?
"+token;
}
...
publicStringgetCSRFToken(){
Useruser=ESAPI.authenticator().getCurrentUser();
if(user==null)returnnull;returnuser.getCSRFToken();}
第三步,在服务器端检查提交令牌与用户会话对象令牌是否匹配。
//thiscodeisfromtheDefaultUtilitiesimplementationinESAPI
PublicvoidverifyCSRFToken(ServletRequestrequest)throws
IntrusionException{Useruser=ESAPI.authenticator().getCurrentUser();
//checkifuserauthenticatedwiththisrequest-noCSRFprotectionrequired
if(request.getAttribute(user.getCSRFToken())!
=null){
return;
}
Stringtoken=request.getParameter(CSRF_TOKEN_NAME);
if(!
user.getCSRFToken().equals(token)){
thrownewIntrusionException("Authenticationfailed",
"PossiblyforgetedrequestwithoutproperCSRFtokendetected");
}
}
第四步,在注销和会话超时,删除用户对象会话和会话销毁。
//thiscodeisintheDefaultUserimplementationofESAPI
Publicvoidlogout(){
ESAPI.Utilities().killCookie(ESAPI.currentResponse(),ESAPI.currentRequest(),
Utilities.REMEMBER_TOKEN_COOKIE_NAME);
Sessionsession=ESAPI.currentRequest().getSession(false);
if(session!
=null){
removeSession(session);
session.invalidate();
}
ESAPI.Utilities().killCookie(ESAPI.currentRequest(),
ESAPI.currentResponse(),"JSESSIONID");
loggedIn=false;
logger.info(Logger.SECURITY_SUCCESS,"Logoutsuccessful");
ESAPI.authenticator().setCurrentUser(User.ANONYMOUS);
}
5.7信息泄露和错处理不当
5.7.1定义
应用程序常常产生错误信息并显示给使用者。
很多时候,这些错误信息是非常有用的攻击,因为它们揭示实施细则或有用的开发信息利用的漏洞。
5.7.2危害
Ø泄露太多的细节(如错误堆栈跟踪信息、SQL语句等等);
Ø登录失败后,通知用户是否用户ID或密码出错——登录失败可能是由于ID或密码错误造成的。
这为一个对关键资产发动蛮力攻击的攻击者提供重要信息。
5.7.3解决方法
5.7.3.1.案例1
通过web.xml配置文件实现
java.lang.Throwable
/error.jsp
5.7.3.2.案例2
针对登录尝试的攻击,可以使用相同的报错信息,比如都是提示"输入的用户名或者密码错误!
"。
5.8残缺的认证和会话管理
5.8.1定义
与认证和会话管理相关的应用程序功能往往得不到正确实施,这就导致攻击者破坏密码、密匙、会话令牌或利用实施漏洞冒充其他用户身份。
5