当不可能准备语句时防止 SQL 注入的最佳方法

发布于 2024-11-14 20:04:03 字数 1850 浏览 1 评论 0原文

我必须在一个存在重大安全问题的旧站点上工作:SQL 注入非常容易执行。

显然,防止此类攻击的最佳方法是转义查询中使用的内容(使用 PDO 准备语句、使用 MySql 的 mysql_real_escape_string 等),但我们不能很快做到这一点:整个站点都是过程化 PHP(没有类) ),查询到处都是“准备好的”,每天都有数百个页面和数千个用户,新版本会尽快到来。

因此,从今天早上开始,每个请求都会调用以下函数,以根据关键字检测可疑的 POST 或 GET 参数。

const SQLI_UNSAFE = 3;
const SQLI_WARNING = 2;
const SQLI_SAFE = 1;
const SQLI_MAIL_DEST = '[email protected]'; 

function sqlicheck() {

    $params = array_merge($_GET, $_POST);
    $is_warning = false;

    foreach($params as $key=>$param) {
        switch(getSafeLevel($param)) {
            case SQLI_SAFE: 
                break;
            case SQLI_WARNING:
                $is_warning = true;
                break;
            case SQLI_UNSAFE: 
                mail(SQLI_MAIL_DEST, 'SQL INJECTION ATTACK', print_r($_REQUEST, true).' '.print_r($_SERVER, true));     
                header('Location: http://monsite/404.php');
                exit();     
            }

    }

    if($is_warning === true) {
        mail(SQLI_MAIL_DEST, 'SQL INJECTION WARNING', print_r($_REQUEST, true).print_r($_SERVER, true));
    }
}
function getSafeLevel($param) {

    $error_words  = array('select%20','drop%20','delete%20','truncate%20','insert%20','%20tbclient','select ','drop ','delete ','truncate ','insert ',);
    $warning_words = array('%20','select','drop','delete','truncate', ';','union');


    foreach($error_words as $error_word) {
        if(stripos($param, $error_word) !== false) return SQLI_UNSAFE;  
    }
    foreach($warning_words as $warning_word) {
        if(stripos($param, $warning_word) !== false) return SQLI_WARNING;   
    }

    return SQLI_SAFE; 
}

这似乎可以检测某些类型的攻击,但这显然是非常基本的。有什么想法可以改进吗?有什么重大问题吗?

I have to work on an old site with major security issues : SQL Injections are really easy to perform.

Obviously, the best way to prevent this kind of attacks is to escape what is used in query (prepare statements with PDO, mysql_real_escape_string with MySql, etc.) but we can't do that quickly : the whole site is procedural PHP (no class), the queries are "prepared" everywhere, there are hundreds of pages and thousands of users everyday, and a new version wil come as soon as possible.

So since this morning the following function is called on each request to detect suspicious POST or GET parameters based on keywords.

const SQLI_UNSAFE = 3;
const SQLI_WARNING = 2;
const SQLI_SAFE = 1;
const SQLI_MAIL_DEST = '[email protected]'; 

function sqlicheck() {

    $params = array_merge($_GET, $_POST);
    $is_warning = false;

    foreach($params as $key=>$param) {
        switch(getSafeLevel($param)) {
            case SQLI_SAFE: 
                break;
            case SQLI_WARNING:
                $is_warning = true;
                break;
            case SQLI_UNSAFE: 
                mail(SQLI_MAIL_DEST, 'SQL INJECTION ATTACK', print_r($_REQUEST, true).' '.print_r($_SERVER, true));     
                header('Location: http://monsite/404.php');
                exit();     
            }

    }

    if($is_warning === true) {
        mail(SQLI_MAIL_DEST, 'SQL INJECTION WARNING', print_r($_REQUEST, true).print_r($_SERVER, true));
    }
}
function getSafeLevel($param) {

    $error_words  = array('select%20','drop%20','delete%20','truncate%20','insert%20','%20tbclient','select ','drop ','delete ','truncate ','insert ',);
    $warning_words = array('%20','select','drop','delete','truncate', ';','union');


    foreach($error_words as $error_word) {
        if(stripos($param, $error_word) !== false) return SQLI_UNSAFE;  
    }
    foreach($warning_words as $warning_word) {
        if(stripos($param, $warning_word) !== false) return SQLI_WARNING;   
    }

    return SQLI_SAFE; 
}

This seems to detect some kinds of attacks but it's clearly very basic. Any ideas to improve it? Any major issue ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

北斗星光 2024-11-21 20:04:03

首先,确保执行查询的数据库用户仅有选择、更新、删除权限。如果用户无法执行删除,则不可能发生这种情况(这假设您的用户永远不需要创建或删除表,但如果他们这样做,您可以创建表级权限来保护大表)。

其次,你的脚本只会告诉你人们正在使用什么;它不会对可能的查询进行站点范围的检查;如果您网站的某个部分不常使用,您将不会收到任何邮件告诉您。最好使用搜索工具梳理代码。

之后,您必须开始修改代码并进行转义和验证,这将需要一段时间。

First, make sure that the database user executing the queries only has select, update, delete permissions. If the user can't execute drop, there's no way it'll happen (this assumes that your users will never need to create or drop tables, but if they do, you can create table level permissions to protect the big tables).

Second, your script will only tell you what people are using; it won't do a site wide check of what queries are possible; if there's a section of your site that isn't used much, you won't get any mail telling you. Better to just comb through the code with a search tool.

After that, you have to start modifying the code and doing escaping and validation, and that's just going to take a while.

原谅过去的我 2024-11-21 20:04:03

为什么不直接使用 real_escape_string() htmlentities() stripslashes 和 php 的过滤器类并记录 SQL 查询,以便您可以看到人们向您发送的内容,使用 sha256 和一些md5 你会没事的,其他事情是为了快速采取行动,只需以二进制格式发送登录数据

Why not just use real_escape_string() htmlentities() stripslashes and filter classes of php and log the SQL queries so that you can see what people are sending you, use sha256 with some md5 you will be ok other thing is for quick action just send login data in binary format

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文