> ​    很多技术研发不了解安全,也不重视安全,只有在自己的服务器被黑掉、被挂马、被脱裤才想起关注安全,但是这个时候,技术架构已经成型、代码已经在线上稳定运行,再亡羊补牢,改代码、改策略,往往成本巨大、而收效很低;所以,开发安全,从娃娃抓起……

一、什么是信息安全?

信息安全是一个庞大的概念,包含大量不同方向的分支技术,但是都涉及几个概念:

以上是信息安全的基本属性,即CIA属性。此外,后期还衍生出其他的属性,如可控性、不可否认性等,总之都是对信息安全概念的补充。

而安全人员的工作,尤其是做企业安全建设的工作,就是围绕保护数据安全的过程,在事前、事中、事后三个阶段,技术上建立扫描、发现、监控、防御、应急、加固等一系列措施,在管理上完善流程、制度、规范,从而使以上几个安全属性得到保障。

概念说了很多,落地到实际是什么样子呢,简单总结了一个安全架构图,比较全的涵盖了企业安全建设的要点。

以上是宏观层面,那具体到每个技术研发同学的身上,最常见的就是对各种安全漏洞、安全风险的处理修复。下面介绍开发过程中常见的安全风险点。

二、SQL注入

sql注入危害很大,也很常见,可以导致企业数据直接被泄漏出去。典型的sql注入漏洞是这样产生的:

void doPost(HttpServletRequest request, HttpServletResponse response){
    JdbcConnection conn = new JdbcConnection();
    final String sql = "select * from product where pname like '%” + request.getParameter("name") + "%'";
    conn.execqueryResultSet(sql);
}

在sql中直接拼接了字符串,导致用户可以通过插入恶意代码来控制sql执行。比如这样:

select * from product where pname like '%name%';

如果name变量输入 qudian';drop database;// 就变成了

select * from product where name like '%qudian';drop database;//%';

那么怎么防御sql注入呢?最简单正确的方式就是预编译。 为什么用预编译,首先要了解sql注入的原理:

> sql注入产生在数据库的编译阶段,拼接字符串时,sql和用户可控的数据部分拼接到一起,一次发送到数据库, 数据库编译时就会把sql指令和数据编译到一起,如果用户可控的数据部分有非法的命令,也会被数据库编译执行,这样就产生了sql注入。

而预编译的方式的简单原理是:

> sql和用户可控的部分是分两次发给数据库的,第一次发sql指令,也就是上个例子的select * from product where pname like '%name%';, 数据库收到后先进行编译,第二次再发送数据qudian';drop database;//,此时数据库不会重新编译第一次收到的指令, 而是把指令和数据区分开,这样不论用户输入的是什么非法数据,数据库都会认为是数据部分,也就不会产生sql注入了。

上面的过程通过抓包可以看到。

预编译的一般简单写法:

// 正常查询
conn = createConnection();
String sql = "select name,password from manager where name=? and password=?";
stat = conn.prepareStatement(sql);
stat.setString(1, name);
stat.setString(2, password);
stat.executeQuery(sql);

// 模糊查询
conn = createConnection();
String sql = "select * from table where url like ?";
stat = con.prepareStatement(sql);
String data="data";
stat.setString(1, "%"+data+"%");
stat.executeQuery(sql);

三、跨站脚本攻击:XSS

很多人不重视XSS,觉得XSS没有大危害,只是能弹个窗有什么用?但实际XSS的危害甚至不弱于远程代码执行等。平时常见的XSS的危害场景:

3.1 XSS是怎么插的?

举个简单的例子,通常正常的表单是这样的:

<input class='txtValue' type='text' name='name' value='<% query.value %>'/>

访问的URL是这样的:http://www.qufenqi.com/1.html?`value=abc` ,最后看到的效果是这样的:

<input class='txtValue' type='text' name='name' value='abc'/>

但是现实总是和理想有差距,黑客通常会这样的URL参数来访问:

http://www.qufenqi.com/1.html?`value=abc'/><script>alert('hello!')</script><div '`

最后得到的就会是

<input class='txtValue' type='text' name='name' value='abc'/><script>alert('hello!')</script><div ''/>

这样就造成了XSS。

这种现象是产生的原因是由于服务端对用户的输入没有做任何处理,因此在浏览器渲染时,用户输入的js代码就会执行。 既然知道了原因,就不难修复,只要让浏览器渲染时js代码不会执行就可以了。

3.2 解决XSS的常用方法

> 由于富文本中有需要用户提交一些html、js、css标签,因此不能直接处理,建议除可能必需保留的标签外,过滤其他危险标签。
>
> - dynsrc、src、action、href、background、bgsound、lowers、value、onmouse*
> - applet、blink、frameset、iframe、object、base、body、head、layer、style
> - basefont、embed、html、link、title、bgdound、frame、player、meta、script
> - vbscript、ms-its、firefoxurl、javascript、shtml、mocha、data、livescript

3.3 解决XSS常见的两种误区

3.3.1 用关键字过滤的方式

​    关键字过滤能解决一部分常见的XSS,但是不能完全避免,通过转义等很多方式可以绕过过滤的方法。

比如这是正常的XSS语句:

<script>alert(1);</script>

但是把它变换一种形式,依然能够达到效果,比如这样:

<script>\u0061\u006c\u0065\u0072\u0074(1);</script>

3.3.2 全局暴力转义

​    不论XSS输出在哪,都用一种方式转义。有时候开发会写一个全局的转义方法,之后不论什么时候在哪出现XSS,都调用这个方法,虽然暂时可行,但时间长了容易引入dom xss,不是一个完美的方案。

四、跨站请求伪造CSRF

首先一个图简单明了的展现了CSRF的过程

> 简单的说就是在用户的某个网站cookie有效时,诱使用户去请求黑客构造好的恶意请求,就能在神不知鬼不觉的情况下进行攻击。

一个发生过的经典例子,某网站后台管理员更改密码的功能,没有校验目前使用的密码,可以直接设置新的管理员密码。 操作请求的参数只有一个新的密码,所以构造链接http://xxx.com/updatepass?newpass=badpass,诱使管理员去请求,就可以默默的改变管理员密码。

下一个问题就是如何诱使受害者去主动请求恶意的链接,方式多种多样,比如在自己的网站上插入这个链接,让用户访问你的网站; 在论坛里插入外链图片,图片链接是恶意的链接,这些都可以。

除此之外,CSRF结合其他漏洞更能达到惊喜的效果,前几年知名的新浪微博蠕虫刷粉丝,可以短时间增长大量的粉丝,就是CSRF和XSS在一起的功效。

那么防御CSRF的方案呼之欲出,目前主流的两种方案:

  - 第一点,通常使用token校验。

    - 第一步,用户登录时,服务端生成token,保存在session中。
    - 第二步,token可以放在表单中或者http请求头中。
    - 第三步,客户端带着token发请求给服务端,服务端校验token。这样通过客户端和session中的token比较,就可以得知请求是否合法。由于token是随机字符串,黑客无法获取,也就无法构造请求了。

  - 第二点,校验referer,这是一个比较简单的实现方式,通过校验referer白名单也可以起到防御CSRF攻击的作用。

    > 不过是这里有个坑,很多开发写正则来取referer,有时候就会造成各种绕过的姿势,比如www.qufenqi.com.baidu.com这样。因此在写正则的时候一定要注意。

五、登录注册安全风险

登录注册的风险点主要有四个:

首先登录,三个必备的要素:用户名、密码、验证码;验证码可以是手机短信验证码或者图形验证码。

通过手机短信验证码既可以识别用户身份,为风控提供基础,又可以防护暴力破解、撞库等批量的攻击行为。 图像验证码则可以人机识别,防护暴力破解、撞库。引入了验证码机制同样引入了额外的安全风险,比如短信验证码的短信炸弹风险、图形验证码的可绕过、可识别等。 此外,也可以加入一些高级的安全策略,辅助分析防护安全风险,如异地登录提醒、记录非常用设备登录、校验用户历史行为。

> 这里简单说下校验用户历史行为:很多产品在设计需要校验身份的场景时,没有完全的考虑各类安全风险,一个常见的例子就是通过短信验证码来找回密码, 产品理想中的场景是短信验证码只能用户自己收到,所以可以确认用户身份,但实际有很多不可控的因素,比如,用户手机丢失的情况。因此,在注册登录点需要综合考虑各种情况。

当然,图形验证码如果设计开发的不当那也是形同虚设了。

一个完善的图形验证码流程是这样的:

  1. 客户端发起一个请求。

  2. 服务端响应并创建一个新的SessionID同时生成一个随机验证码。

  3. 服务端将验证码和SessionID一并返回给客户端。

  4. 客户端提交验证码连同SessionID给服务端。

  5. 服务端验证验证码同时销毁当前会话,返回给客户端结果。

如果整个流程中的某个环节处理不当,则会产生各种问题:

  1. 验证码不过期,可重复使用。这是比例最大的验证码安全风险,产生这种现象的主要原因是验证码的刷新是在前端进行,服务端的功能只有接收验证码判断对错,并没有sessionid的机制,这样只要拦截请求每次使用这个验证码重新发包,就可以绕过验证码的策略做各种攻击尝试。正确的做法是每次校验验证码之后,服务端要重新生成验证码。

  2. 验证码输出到客户端。这种问题也很常见,很多验证码的逻辑是在请求验证码时,服务端不只返回验证码图片,还返回图片里的内容,这样通过抓取返回中的验证码内容字段就可以绕过验证码的人机识别过程。争取的做法是服务端返回时,不要返回验证码内容,直接返回一张图片即可。

  3. 验证码前端生成,前端校验。这里涉及安全的一个原则:永远不要信任用户端的输入。所有前端的代码都是可以被用户修改的,因此如果在前端做验证码处理,黑客则可以通过修改前端代码自己生成,自己校验,完全绕过验证码的逻辑。

  4. 验证码可以被识别。这是目前验证码的一个难题。现在图像识别的技术非常成熟,前端的数字字符验证码,即使增加了背景、干扰、粘连等措施,也可以被轻松识别。因此验证码技术现在逐渐发展成通过用户行为识别和找不同来做人机识别。比如滑动验证码、12306那类的验证码。

  

六、第三方系统的安全

很多产品避免不了和第三方产品的互相调用,但是在调用过程中如果不注意安全控制,很容易因为第三方系统的安全问题,导致自己的安全风险。

以前遇到过一个例子,某电商网站扩展二手回收业务,和某二手回收网站合作,会将自己的一些用户信息传给二手回收的系统,结果因为对方的安全做的不够完善,导致自己的大量用户信息被泄漏。 造成了很严重的影响。但是第三方的系统安全我们是控制不了的,因此我们只能互相调用的接口传输过程中加入安全策略。

通常有以下几种做法:

简单的介绍了线上常见的几种安全风险,接下来说说几点安全基本的原则,也是各种安全方案的思想。 通过这几个原则可以扩展出很多成熟的安全方案:

想要说的也就这么多,其实很多问题没有深入,只是做了总结介绍,很多风险点由于篇幅关系也没有介绍,最后提醒大家:一定要注意线上安全!!!

源链接

Hacking more

...