代码安全

 

随着互联网深入到各行各业,越来越多的应用系统、网站等被人类通过网络连接、访问。如何保障系统、网站不会因黑客的恶意攻击而导致系统崩溃、数据泄露等安全问题,解决此问题的最根本的手段还是要回归到代码上面,只有写出的代码是安全的、是无懈可击的、没有任何逻辑漏洞,才能杜绝一切安全问题。本文从以下几个方面讲述系统漏洞产生的原理及如何预防这些漏洞,做到代码安全。内容比较浅显,不做深入阐释。

Sql注入

XSS攻击

CSRF攻击

SSRF攻击

任意文件上传和下载

应用服务器安全性优化

 

sql注入

什么是sql注入呢?下面以一个通俗的例子来理解。

一个正常的sql语句:

Select password from user where username=’admin’

在实际实现中(以Java为例):

String username = request.getParameter(“username”);
String sql = “select password from user where username=’”+username+”’”;

当通过表单向后端传入username参数值为admin时,sql就变成上面所示的语句,sql执行就得到admin用户对于的password。如果,用户恶意输入 username参数为:

‘ and 1=2 union select ’123456      (mysql数据库)
或者
‘ and 1=2 union select ’123456’ from dual where ‘1’=’1      (oracle数据库)

那么sql语句就变成:

Select password from user where username =’’ and 1=2 union select ‘123456’;
或者
Select password from user where username =’’ and 1=2 union select ‘123456’ from dual where ‘1’=’1’;

执行sql,得到结果总是123456。

这种将sql指令输入到原来的sql指令中执行的方式,就是所谓的sql注入攻击。攻击者通过精心构造输入参数,可以在相当大的范围内以当前用户的权限读写数据库。

由上面可知,sql注入攻击根本原因是拼接sql语句

因此,sql注入漏洞防范的最好的方法是使用参数化查询。

String sqlcmd = "select Password from CMS_SYS_USERS where Username = ?";
    PreparedStatement stmt =con.prepareStatement(sqlcmd);
stmt.setString(1, request.getParameter("UserName"));

在参数化查询中,数据库在读取参数前首先完成对SQL语句的编译。不论输入的参数如何、内容转义与否,都不会作为SQL代码(而是二进制数据)来执行SQL语句。

XSS攻击

XSS就是跨站脚本攻击(Cross Site Scripting),是为了不和层叠样式表(Cascading Style Sheets,CSS)的缩写混淆。XSS漏洞形成原理:

一段正常的JSP代码:

<span><%=title%></span>

将变量title显示在页面上。这种做法本身是功能需要,合情合理但是如果参数title的内容是由恶意用户控制的:

<script>恶意JS代码</script>

页面内容就会变成:

<span><script>恶意JS代码</script></span>

加载该页面的用户就会在浏览器上执行这段JS代码。

总之就是:XSS漏洞的根本原因是构造动态文档时,未进行正确的编码或转义。

如何防范XSS攻击呢?对输出数据使用HtmlEncoder对一些字符做转义处理,所有HTML和XML中输出的数据,都应该做html escape转义:

需作转义的字符 字符实体编码
& &amp;
< &lt;
> &gt;
" &quot;
' &#39;
/ &#47;
<span><%=ESAPI.encoder().EncoderForHTML("<script>alert(document.cookie)</script>","HTML")%></span>
                                      
                                           ↓

<span>&lt;script&gt;alert(document.cookie)&lt;/script&gt;</span>

CSRF攻击

CSRF就是跨站请求伪造攻击(Cross-Site Request Forgery),是一种劫持被攻击者浏览器发送HTTP请求到目标网站触发某种操作的漏洞。在原理上是一种与XSS相左的攻击方式,其最终的作用对象是服务器上的WEB程序,是远端的,而XSS的最终作用对象是浏览器,是本地的。攻击者在用户浏览网页时,利用页面元素(例如img的src),强迫受害者的浏览器向Web应用程序发送一个改变用户信息的请求。由于发生CSRF攻击后,攻击者是强迫用户向服务器发送请求,所以会造成用户信息被迫修改,更严重者引发蠕虫攻击。

CSRF攻击可以从站内和站外发起:

  1. 从站内发起CSRF攻击,需要利用网站本身的业务,比如“自定义头像”功能,恶意用户指定自己的头像URL是一个修改用户信息的链接,当其他已登录用户浏览恶意用户头像时,会自动向这个链接发送修改信息请求。站内CSRF攻击通常结合XSS一同使用,如下例子,恶意攻击者在某一论坛,在留言板中输入如下内容:
    <form name="form1" method="post" action="http://10.81.10.201/cms/admin/user.action.php">
     <input name="act" value="add">
         <input name="username" value="hacker">
         <input name="password" value="hacker">
         <input name="password2" value="hacker">
         <input name="userid" value="0">
    </form>
    <script language="javascript">
    document.form1.submit();
    </script>
    

    当系统管理员登录系统并查看留言时,就会在管理员完全没有察觉的情况下,执行了恶意攻击者的JS语句去创建用户名和密码都为hacker的用户。这样恶意攻击者就通过伪造请求的方式创建了hacker这个用户。

  2. 从站外发送请求,则需要恶意用户在自己的服务器上,放一个自动提交修改个人信息的htm页面,并把页面地址发给受害者用户,受害者用户打开时,会发起一个请求。如果恶意用户能够知道网站管理后台某项功能的URL,就可以直接攻击管理员,强迫管理员执行恶意用户定义的操作。站外攻击实例如下:

1)在页面中加入一个<img>标签,浏览器就会发送一个请求,以获取其src属性引用的值

2)攻击者将敏感操作的URI作为src

3)继承Cookie,以浏览者的身份作敏感访问并操作

4)危害:在用户无意识情况下进行危险操作

攻击者为了攻击某站点的登录用户,可以构造2个HTML页面。首先在页面a.htm中写一个没有面积的iframe,以免受害者看到提交结果而产生警觉:

<iframe src="b.htm" width="0" height="0"></frame>

然后在页面b.htm中,写入CSRF攻击代码:

<form id="modify" action="http://xx.com/servlet/modify" method="POST">
<input name="email">
<input name="userid">
</form>
<script>
document.getElementById("modify").submit();
</script>

接下来,攻击者需要设法诱骗合法用户访问a.htm,一旦用户打开a.htm,就会自动提交表单,从而达到CSRF攻击的目的。

如何防范CSRF攻击呢?

判断该请求是否为网站内已知正常的功能页面,查看http请求头部的referer字段,referer总是指向请求的来源,若来源是正常或已知的网站,那么就不存在CSRF攻击。但是这个方法并不是绝对的,referer是可以被伪造的。另外,这种方式对于站内攻击也是无效的。对于csrf攻击最有效的手段就是使用不可猜测的字段。如下:

攻击者无法预测其他用户的随机TOKEN值,所以无法构造跨站链接或表单。类似的,图形验证码、短信验证码、UKey、要求再次输入密码等方式均对CSRF有效。

SSRF攻击

SSRF就是服务端请求伪造(Server-Side Request Forgery)攻击,即服务端的网络访问能够被攻击者操纵所导致的安全漏洞。例如下面代码:

攻击者若提供一个恶意的url,那么服务器端就会出现异常。因此,SSRF往往意味着僵尸网络,恶意代理,甚至跳板入侵内网。

任意文件上传和任意文件下载

任意文件上传,即服务器端没有对用户上传的文件类型做校验或者校验不完整,导致用户可以上传恶意文件到服务器。如下面代码:

String filePath = getServletContext().getRealPath("/") + "GoodsImages";
File file = new File(filePath);
String saveName = UUID.randomUUID().toString() + ".";
if (!file.exists()){
file.mkdir();
}
SmartUpload su = new SmartUpload();
su.initialize(getServletConfig(), request, response); 
su.upload();
saveName = saveName + su.getFiles().getFile(0).getFileExt();
String fileName = filePath + "/" + saveName;
if (su.getFiles().getFile(0).isMissing()){
out.print("<script>alert('请选择上传的图片!'),window.location='GoodsAdd.jsp'</script>");
return;
}
su.getFiles().getFile(0).saveAs(fileName);

上传图片时,没有限制上传文件的类型,此时上传的是一个jsp文件,如果jsp中含有恶意代码,那么系统很有可能受到攻击。因此,在上传文件时,一定要判断文件的类型,是否合法。判断文件类型要通过文件的魔数(Java中有相应方法),而不是简单的截取文件后缀名。

任意文件下载漏洞形成的原因:在日常开发中,常见这样的文件下载功能:

String filename = request.getParameter("file");
    String absolutePath = WEB_PATH + "/" + filename;
WebUtils.downFile(absolutePath);

提交的文件路径没有进行过滤,就与其它目录路径进行字符串拼接。此种情况下,利用../来遍历目录,就可以下载任意文件。在特定情况下,攻击者即使不使用“..”来遍历目录,也能够下载到一些敏感文件:

String filename = request.getParameter("/WEB-INF/web.xml");

虽然和任意文件上传的名字上很接近,但限制文件后缀名的方法在任意文件下载漏洞中行不通:

String filename = request.getParameter("file");
    if(!filename.endsWith(".jpg")&&!filename.endsWith(".bmp"){
        throw new SecturityException("只允许下载jpg或bmp文件");
    }
    String absolutePath = WEB_PATH + "/" + filename;
    WebUtils.downFile(absolutePath);
    此时使用类型这样的Payload:
    xx.jsp?file=..%2F..%2F..%2Fetc%2Fpasswd%00%.bmp

在多数C/C++程序(比如操作系统)中,字符%00被认为是字符串的结束(而非忽略该字符)。在访问文件时,空字符可以截断字符串,从而绕过下载文件类型限制。

任意文件下载漏洞防范措施就是:尽量避免由用户干涉文件访问的路径,而是在服务端直接确定文件路径。

应用服务器安全性优化

曾经参与了一款保密产品的申请工作,其中应用服务器的安全性是保密局对产品的要求之一,下面以tomcat为例,如何使其安全性达到要求:

  1. 修改server.xml文件中的<Server port="8005" shutdown="SHUTDOWN">。从安全的角度上考虑,我们需要把这个shutdown指令改成一个别人不容易猜测的字符串,可以同时把端口也改了。否则telnet到服务器的8005端口,输入“SHUTDOWN”,然后回车,服务器会关闭。
  2. 处理好tomcat的管理安全。删除webapps文件夹下的manager、host-manager和admin文件夹。将conf文件夹下的tomcat-users.xml中所有用户信息配置注释掉。
  3. 运行错误网页。如果找不到网页即出现404错误,会显示服务器版本号,服务器配置也一目了然。避免这一现象,配置404页面。在web.xml文件中倒数第二行,添加以下内容:
    <error-page>
        <error-code>404</error-code>
       <location>/404.jsp</location>
      </error-page>
      <error-page>
        <error-code>500</error-code>
        <location>/500.jsp</location>
     	 </error-page>
    
  4. 关闭8009端口。8009端口是tomcat和apache的mod_proxy_ajp,mod_jk沟通的端口,用不到就关闭它,将server.xml文件中的这段代码注释掉:
    <Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>

     

  5. 关闭war自动部署。Tomcat默认是开启war自动部署的,为了防止被植入木马等恶意程序,要关闭自动部署功能,修改server.xml文件中的这段代码:<Host appBase="webapps" autoDeploy="false" name="localhost" unpackWARs="true">,将autoDeploy属性值修改为false。
  6. 禁止列出目录。如果设置不当,就会列出Web当前目录中的所有文件,然而在Tomcat也不例外。如果浏览者可以在客户端浏览Web目录,那将会存在较大的安全隐患,因此我们要确认Tomcat的设置中禁止列目录。修改\conf\web.xml下的:
    <init-param>
    <param-name>listings</param-name>
    <param-value>false</param-value>
    </init-param>

     

  7. 开启安全日志功能,安全日志保存到logs文件夹中,安全日志默认是开启的,检查一下是否存在这个tomcat_home/logs文件夹。

注:为了更好的学习,本文引用了别人的一些文字和语言,望谅解!

发布了25 篇原创文章 · 获赞 29 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览