python Web安全之防止SQL注入

伴随着Web2.0、社交网络、微博等一系列新型互联网产品的兴起,基于Web环境的互联网应用越来越广泛,Web攻击的手段也越来越多样,Web安全史上的一个重要里程碑是大约1999年发现的SQL注入攻击,之后的XSS,CSRF等攻击手段愈发强大,Web攻击的思路也从服务端转向了客户端,转向了浏览器和用户。

在安全领域,一般用帽子的颜色来比喻黑客的善与恶,白帽子是指那些工作在反黑客领域的技术专家,这个群体是”善”的的象征;而黑帽子则是指那些利用黑客技术造成破坏甚至谋取私利造成犯罪的群体,他们是”恶”的代表。

“白帽子”和”黑帽子”是两个完全对立的群体。对于黑帽子而言,他们只要找到系统的一个切入点就可以达到入侵破坏的目的,而白帽子必须将自己系统所有可能被突破的地方都设防,以保证系统的安全运行。

这看起来好像是不公平的,但是安全世界里的规则就是这样,可能我们的网站1000处都布防的很好,考虑的很周到,但是只要有一个地方疏忽了,攻击者就会利用这个点进行突破,让我们另外的1000处努力白费。

常见攻击方式

一般说来,在Web安全领域,常见的攻击方式大概有以下几种:
1、SQL注入攻击
2、跨站脚本攻击 - XSS
3、跨站伪造请求攻击 - CSRF
4、文件上传漏洞攻击
5、分布式拒绝服务攻击 - DDOS

SQL注入实例之参数化


from pymysql import *

def main():

    find_name = input("请输入物品名称:")

    # 创建Connection连接
    conn = connect(host='localhost',port=3306,user='root',password='mysql',database='jing_dong',charset='utf8')
    # 获得Cursor对象
    cs1 = conn.cursor()


    # # 非安全的方式
    # # 输入 " or 1=1 or "   (双引号也要输入)
    # sql = 'select * from goods where name="%s"' % find_name
    # print("""sql===>%s<====""" % sql)
    # # 执行select语句,并返回受影响的行数:查询所有数据
    # count = cs1.execute(sql)

    # 安全的方式
    # 构造参数列表
    params = [find_name]
    # 执行select语句,并返回受影响的行数:查询所有数据
    count = cs1.execute('select * from goods where name=%s', params)
    # 注意:
    # 如果要是有多个参数,需要进行参数化
    # 那么params = [数值1, 数值2....],此时sql语句中有多个%s即可 

    # 打印受影响的行数
    print(count)
    # 获取查询的结果
    # result = cs1.fetchone()
    result = cs1.fetchall()
    # 打印查询的结果
    print(result)
    # 关闭Cursor对象
    cs1.close()
    # 关闭Connection对象
    conn.close()

if __name__ == '__main__':
    main()

这种用法就是常见的拼接字符串导致sql注入漏洞的产生。看到这个突然想到上个礼拜drupal水滴的那个漏洞,其并不是预编译语句被绕过了。而是在构造带入的预编译语句的时候拼接了用户输入字符串,还未带入查询的预编译语句已经被注入了,之后带入正确的参数,最后被注入了

正确用法:
execute() 函数本身有接受sql语句参数位的,可以通过python自身的函数处理sql注入问题。

使用如此参数带入方式,python会自动过滤params中的特殊字符,制止SQL注入的产生。

execute()函数本身就有接受SQL语句变量的参数位,只要正确的使用(直白一点就是:使用”逗号”,而不是”百分号”)就可以对传入的值进行correctly转义,从而避免SQL注入的发生。

如何确定SQL注入漏洞

通过以上的实例,我们仍然还会有疑问:黑客并不知道我们程序代码的逻辑和SQL语句的写法,他是如何确定一个网站是否存在SQL注入漏洞呢?一般说来有以下2种途径:

1、错误提示

如果目标Web网站开启了错误显示,攻击者就可以通过反复调整发送的参数、查看页面打印的错误信息,推测出Web网站使用的数据库和开发语言等重要信息。

2、盲注

除非运维人员疏忽,否则大部分的Web运营网站应该都关闭了错误提示信息,此时攻击者一般会采用盲注的技巧来进行反复的尝试判断。 仍然以上面的数据表user为例,我们之前的查看会员详情页面的url地址为userinfo.php?username=plhwin,此时黑客分别访问userinfo.php?username=plhwin' AND 1=1-- hackuserinfo.php?username=plhwin' AND 1=2-- hack,如果前者访问能返回正常的信息而后者不能,就基本可以判断此网站存在SQL注入漏洞,因为后者的1=2这个表达式永远不成立,所以即使username传入了正确的参数也无法通过,由此可以推断这个页面存在SQL注入漏洞,并且可以通过username参数进行注入。

如何防御SQL注入

对于服务器配置层面的防范,应该保证生产环境的Webserver是关闭错误信息的,比如PHP在生产环境的配置文件php.ini中的display_errors应该设置为Off,这样就关闭了错误提示,下面我们更多的从编码的角度来看看如何防范SQL注入。

上面用两个实例分析了SQL注入攻击的技巧,可以看到,但凡有SQL注入漏洞的程序,都是因为程序要接受来自客户端用户输入的变量或URL传递的参数,并且这个变量或参数是组成SQL语句的一部分,对于用户输入的内容或传递的参数,我们应该要时刻保持警惕,这是安全领域里的「外部数据不可信任」的原则,纵观Web安全领域的各种攻击方式,大多数都是因为开发者违反了这个原则而导致的,所以自然能想到的,就是从变量的检测、过滤、验证下手,确保变量是开发者所预想的。

1、检查变量数据类型和格式

如果你的SQL语句是类似where id={$id}这种形式,数据库里所有的id都是数字,那么就应该在SQL被执行前,检查确保变量id是int类型;如果是接受邮箱,那就应该检查并严格确保变量一定是邮箱的格式,其他的类型比如日期、时间等也是一个道理。总结起来:只要是有固定格式的变量,在SQL语句执行前,应该严格按照固定格式去检查,确保变量是我们预想的格式,这样很大程度上可以避免SQL注入攻击。

比如,我们前面接受username参数例子中,我们的产品设计应该是在用户注册的一开始,就有一个用户名的规则,比如5-20个字符,只能由大小写字母、数字以及一些安全的符号组成,不包含特殊字符。此时我们应该有一个check_username的函数来进行统一的检查。不过,仍然有很多例外情况并不能应用到这一准则,比如文章发布系统,评论系统等必须要允许用户提交任意字符串的场景,这就需要采用过滤等其他方案了。

2、过滤特殊符号

对于无法确定固定格式的变量,一定要进行特殊符号过滤或转义处理。以PHP为例,通常是采用addslashes函数,它会在指定的预定义字符前添加反斜杠转义,这些预定义的字符是:单引号 (') 双引号 (") 反斜杠 (\) NULL

相信大家都还对2011年爆出的CSDN拖库事件记忆犹新,这件事情导致CSDN处在风口浪尖被大家痛骂的原因就在于他们竟然明文存储用户的密码,这引发了科技界对用户信息安全尤其是密码安全的强烈关注,我们在防范SQL注入的发生的同时,也应该未雨绸缪,说不定下一个被拖库的就是你,谁知道呢。

在Web开发中,传统的加解密大致可以分为三种:

1、对称加密:即加密方和解密方都使用相同的加密算法和密钥,这种方案的密钥的保存非常关键,因为算法是公开的,而密钥是保密的,一旦密匙泄露,黑客仍然可以轻易解密。常见的对称加密算法有:AESDES等。

2、非对称加密:即使用不同的密钥来进行加解密,密钥被分为公钥和私钥,用私钥加密的数据必须使用公钥来解密,同样用公钥加密的数据必须用对应的私钥来解密,常见的非对称加密算法有:RSA等。

3、不可逆加密:利用哈希算法使数据加密之后无法解密回原数据,这样的哈希算法常用的有:md5SHA-1等。

在我们上面登录系统的示例代码中,$md5password = md5($password);从这句代码可以看到采用了md5的不可逆加密算法来存储密码,这也是多年来业界常用的密码加密算法,但是这仍然不安全。为什么呢?

这是因为md5加密有一个特点:同样的字符串经过md5哈希计算之后生成的加密字符串也是相同的,由于业界采用这种加密的方式由来已久,黑客们也准备了自己强大的md5彩虹表来逆向匹配加密前的字符串,这种用于逆向反推MD5加密的彩虹表在互联网上随处可见,在Google里使用md5 解密作为关键词搜索,一下就能找到md5在线破解网站,把我们插入用户数据时候的MD5加密字符串e10adc3949ba59abbe56e057f20f883e填入进去,瞬间就能得到加密前的密码:123456。当然也并不是每一个都能成功,但可以肯定的是,这个彩虹表会越来越完善。

所以,我们有迫切的需求采用更好的方法对密码数据进行不可逆加密,通常的做法是为每个用户确定不同的密码加盐(salt)后,再混合用户的真实密码进行md5加密

猜你喜欢

转载自blog.csdn.net/Fantasy_worm/article/details/85680921