• 159.SQL注入的实现和防御措施


    sql注入:

    所谓sql注入,就是通过把sql命令插入到表单中或页面请求的查询字符串中,最终达到欺骗服务器执行恶意的sql命令。具体来说,它是利用现有的应用程序,将(恶意的)sql命令注入到后台数据库引擎执行的能力,它也可以通过在Web表单中输入(恶意)SQL语句得到一个存在安全漏洞的网站上的数据库,而不是按照设计者的意图去执行sql语句。比如先前的很多影视网站泄露VIP会员密码大多数就是通过Web表单递交查询字符串爆出的。

    (1)现在我们有一个sql_user表,表结构如下:

    from django.db import models
    from django.core import validators
    
    
    class User(models.Model):
        username = models.CharField(max_length=20)
        password = models.CharField(max_length=24)
        telephone = models.CharField(max_length=11, validators=[validators.RegexValidator(r"1[345678]d{9}")])
    
        class Meta:
            db_table = 'sql_user'
    

    (2)然后我们使用原生sql语句实现以下需求:

    (1)实现一个根据用户id获取用户详情的视图,示例代码如下:
    from django.http import HttpResponse
    from django.db import connection
    from django.shortcuts import render
    
    
    def index(request):
        cursor = connection.cursor()
        user_id = request.GET.get('id')
        context = {}
    
        if user_id:
            cursor.execute("select id,username from sql_user where id=%s"%user_id)
            users = cursor.fetchall()
            for user in users:
                print(user)
            context['users'] = users
            return render(request, 'sql.html', context=context)
        else:
            return HttpResponse('该用户不存在!!!')
    
    (2)正常情况,用户可以使用查询字符串的形式访问该网页,并且查询用户的详情,可以输入:http://127.0.0.1:8000/sql/?id=2, 这样的话,就会返回给用户数据库中id为2的用户详情。可是,如果用户在这个时候,进行sql注入,比如,输入:http://127.0.0.1:8000/sql/?id=2 or 1=1,很显然,1=1这样的条件是永远为True的,这样的话,就会返回给用户数据库中存在的所有用户的数据,就会造成用户信息的泄露。
    (3)根据用户名提取用户相关的信息,示例代码如下:
    from django.http import HttpResponse
    from django.db import connection
    from django.shortcuts import render
    
    
    def index(request):
        cursor = connection.cursor()
        username = request.GET.get('username')
        context = {}
        if username:
            cursor.execute("select id, username from sql_user where username='%s'"%username)
            users = cursor.fetchall()
            for user in users:
                print(user)
            context['users'] = users
            return render(request, 'sql.html', context=context)
        else:
            context['users'] = '您输入的用户不存在!'
            return render(request, 'sql.html', context=context)
    
    注意,如果在执行sql语句的时候没有在%s两边用单引号包裹,那么在输入url的时候一定要将username对应的值加上单引号http://127.0.0.1:8001/sql/?username='孤烟逐云',否者的话,会报错:“OperationalError at /sql/(1054, "Unknown column '孤烟逐云' in 'where clause'")”。但是,如果我们在执行sql语句的时候,在%s两边加上单引号,那么在url中输入查询字符串的时候,就不用加单引号了。
    正常情况下,我们应该输入:http://127.0.0.1:8001/sql/?username=孤烟逐云 ,网页就会返回给我们查询到的用户的详情。但是,如果我们不遵循设计者的意愿,输入http://127.0.0.1:8001/sql/?username=孤烟逐云' or '1=1很显然,这个结果永远为True 。那么,就会给用户返回数据库中所有的用户信息,并且此时不管你输入的username是否存在数据库中,也不管你后面输入的是1=4还是1=3都会返回数据库中所有的信息。其实此时已经破坏了网页的结构。

    sql注入防御:

    通过传递一些恶意代码来破坏原有的sql语句以便达到自己的目的。那么我们该如何防御sql注入呢? 归类起来主要有以下几点:

    (1)永远不要信任用户的输入。对用户的输入进行校验,可以通过正则表达式,或限制长度,对单引号和双引号进行转换等。
    (2)永远不要使用动态拼接sql,可以使用参数化的sql或者直接使用存储过程进行数据查询存取,比如:
    sql = "select id, username from sql_user where username=%s"
    cursor.execute(sql, (username,))
    <!--参数化的形式execute(sql语句,(参数,)),其中参数后面的逗号表示execute()传入的是一个元组。-->
    
    (3)永远不要使用管理员权限的数据库连接,为每个应用使用单独的权限有限的数据库连接。
    (4)不要把机密信息直接存放,加密或者hash掉密码和敏感的信息。
    (5)应用的异常信息应该给出尽可能少的提示,最好使用自定义的错误信息对原始信息进行包装。

    在Django中如何防御sql注入:

    (1)使用ORM来做数据的增删改查,因为ORM使用的是参数化的形式执行sql语句。
    (2)如果要执行原生sql语句,那么建议不要使用拼接的sql,而是使用参数化的形式。
    始于才华,忠于颜值;每件事情在成功之前,看起来都是天方夜谭。一无所有,就是无所不能。
  • 相关阅读:
    弹出层
    jquery点击切换显示
    jquery使用css类名和id获取元素
    jquery选择器之基本筛选选择器
    jquery选择器之层级选择器
    jquery选择器之全选择器
    jquery选择器之元素选择器
    选择器之类选择器
    jquery选择器之ID选择器
    DOM对象转化为jquery对象
  • 原文地址:https://www.cnblogs.com/guyan-2020/p/12348076.html
Copyright © 2020-2023  润新知