首页 文章

如何从“Bobby Tables”XKCD漫画中注入SQL?

提问于
浏览
1015

只看:

XKCD Strip
(来源:https://xkcd.com/327/

这个SQL做了什么:

Robert'); DROP TABLE STUDENTS; --

我知道 '-- 都是评论,但是_1111857_这个词也没有被评论,因为它是同一行的一部分?

12 回答

  • 1040

    It drops the students table.

    学校计划中的原始代码可能看起来像

    q = "INSERT INTO Students VALUES ('" + FNMName.Text + "', '" + LName.Text + "')";
    

    这是将文本输入添加到查询中的天真方式,非常糟糕,正如您将看到的那样 .

    在第一个名称,中间名称文本框FNMName.Text(即 Robert'); DROP TABLE STUDENTS; -- )和最后一个名称文本框LName.Text(让我们称之为 Derper )的值与查询的其余部分连接后,结果现在实际上是两个查询分隔由statement terminator(分号) . 第二个查询已经 injected 成为第一个 . 当代码对数据库执行此查询时,它将如下所示

    INSERT INTO Students VALUES ('Robert'); DROP TABLE Students; --', 'Derper')
    

    用简单的英语粗略地翻译成两个查询:

    将新记录添加到Students表,其名称值为'Robert'

    删除学生表

    超过第二个查询的所有内容都是marked as a comment--', 'Derper')

    学生 ' 中的 ' 收尾string delimiter . 由于学生's name is a string, it'需要语法上完成假设查询 . 注入攻击仅在它们注入的SQL查询产生有效SQL时才有效 .

    根据dan04的敏锐评论再次编辑

  • 561

    假设该名称用于变量 $Name . 然后运行此查询:

    INSERT INTO Students VALUES ( '$Name' )
    

    代码错误地将用户提供的任何内容作为变量放置 . 您希望SQL为:

    插入学生 Value 观('Robert Tables`)

    但聪明的用户可以提供他们想要的任何东西:

    插入学生 Value 观('Robert'); DROP TABLE学生; - ')

    你得到的是:

    INSERT INTO Students VALUES ( 'Robert' );  DROP TABLE STUDENTS; --' )
    

    -- 只评论该行的其余部分 .

  • 149

    正如其他人已经指出的那样, '); 关闭了原始声明,然后是第二个声明 . 大多数框架(包括PHP等语言)到目前为止都有默认的安全设置,不允许在一个SQL字符串中使用多个语句 . 例如,在PHP中,您只能使用 mysqli_multi_query 函数在一个SQL字符串中运行多个语句 .

    但是,您可以通过SQL注入操作现有的SQL语句,而无需添加第二个语句 . 假设你有一个登录系统,用这个简单的选择来检查用户名和密码:

    $query="SELECT * FROM users WHERE username='" . $_REQUEST['user'] . "' and (password='".$_REQUEST['pass']."')";
    $result=mysql_query($query);
    

    如果您提供 peter 作为用户名并且 secret 作为密码,则生成的SQL字符串将如下所示:

    SELECT * FROM users WHERE username='peter' and (password='secret')
    

    一切安好 . 现在假设您提供此字符串作为密码:

    ' OR '1'='1
    

    然后生成的SQL字符串将是这样的:

    SELECT * FROM users WHERE username='peter' and (password='' OR '1'='1')
    

    这样您就可以在不知道密码的情况下登录任何帐户 . 因此,您不需要能够使用两个语句来使用SQL注入,但如果您能够提供多个语句,则可以执行更具破坏性的操作 .

  • 27

    不, ' 不是SQL中的注释,而是分隔符 .

    妈妈认为数据库程序员提出的请求如下:

    INSERT INTO 'students' ('first_name', 'last_name') VALUES ('$firstName', '$lastName');
    

    (例如)添加新学生,其中 $xxx 变量内容直接取自HTML表单,而不检查格式或转义特殊字符 .

    因此,如果 $firstName 包含 Robert'); DROP TABLE students; -- ,数据库程序将直接在DB上执行以下请求:

    INSERT INTO 'students' ('first_name', 'last_name') VALUES ('Robert'); DROP TABLE students; --', 'XKCD');
    

    即 . 它会在插入语句的早期终止,执行破解者想要的任何恶意代码,然后注释掉可能存在的任何剩余代码 .

    嗯,我太慢了,我在橙色乐队之前已经看到了8个答案...... :-)似乎是一个热门话题 .

  • 15

    TL; DR

    -- The application accepts input, in this case 'Nancy', without attempting to
    -- sanitize the input, such as by escaping special characters
    school=> INSERT INTO students VALUES ('Nancy');
    INSERT 0 1
    
    -- SQL injection occurs when input into a database command is manipulated to
    -- cause the database server to execute arbitrary SQL
    school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
    INSERT 0 1
    DROP TABLE
    
    -- The student records are now gone - it could have been even worse!
    school=> SELECT * FROM students;
    ERROR:  relation "students" does not exist
    LINE 1: SELECT * FROM students;
                          ^
    

    这会删除(删除)学生表 .

    (此答案中的所有代码示例都在PostgreSQL 9.1.2数据库服务器上运行 . )

    为了清楚地说明发生了什么,让我们用一个只包含name字段的简单表来尝试这个并添加一行:

    school=> CREATE TABLE students (name TEXT PRIMARY KEY);
    NOTICE:  CREATE TABLE / PRIMARY KEY will create implicit index "students_pkey" for table "students"
    CREATE TABLE
    school=> INSERT INTO students VALUES ('John');
    INSERT 0 1
    

    假设应用程序使用以下SQL将数据插入表中:

    INSERT INTO students VALUES ('foobar');
    

    foobar 替换为学生的实际姓名 . 正常的插入操作如下所示:

    --                            Input:   Nancy
    school=> INSERT INTO students VALUES ('Nancy');
    INSERT 0 1
    

    当我们查询表时,我们得到这个:

    school=> SELECT * FROM students;
     name
    -------
     John
     Nancy
    (2 rows)
    

    当我们将Little Bobby Tables的名字插入表格时会发生什么?

    --                            Input:   Robert'); DROP TABLE students; --
    school=> INSERT INTO students VALUES ('Robert'); DROP TABLE students; --');
    INSERT 0 1
    DROP TABLE
    

    这里的SQL注入是学生终止语句的名称的结果,包括一个单独的 DROP TABLE 命令;输入末尾的两个破折号用于注释掉任何可能导致错误的剩余代码 . 输出的最后一行确认数据库服务器已删除该表 .

    重要的是要注意,在 INSERT 操作期间,应用程序不检查任何特殊字符的输入,因此允许将任意输入输入SQL命令 . 这意味着恶意用户可以插入通常用于用户输入的字段,特殊符号(如引号)以及任意SQL代码,以使数据库系统执行它,因此SQL injection .

    结果?

    school=> SELECT * FROM students;
    ERROR:  relation "students" does not exist
    LINE 1: SELECT * FROM students;
                          ^
    

    SQL注入是操作系统或应用程序中远程arbitrary code execution漏洞的数据库 . 成功的SQL注入攻击的潜在影响不容小觑 - 取决于数据库系统和应用程序配置,攻击者可以使用它来导致数据丢失(如本例所示),获取未经授权的数据访问,甚至执行主机本身的任意代码 .

    正如XKCD漫画所指出的,防止SQL注入攻击的一种方法是清理数据库输入,例如通过转义特殊字符,以便它们不能修改底层SQL命令,因此不会导致执行任意SQL代码 . 如果使用参数化查询,例如在ADO.NET中使用SqlParameter,则输入将至少自动清理以防止SQL注入 .

    但是,在应用程序级别清理输入可能无法阻止更高级的SQL注入技术 . 例如,there are ways to circumvent the mysql_real_escape_string PHP function . 为了增加保护,许多数据库系统都支持prepared statements . 如果在后端中正确实现,预处理语句可以通过将数据输入视为与命令的其余部分在语义上分开来使SQL注入不可能 .

  • 15

    说你天真地写了这样的学生创作方法:

    void createStudent(String name) {
        database.execute("INSERT INTO students (name) VALUES ('" + name + "')");
    }
    

    有人输入名字 Robert'); DROP TABLE STUDENTS; --

    在数据库上运行的是这个查询:

    INSERT INTO students (name) VALUES ('Robert'); DROP TABLE STUDENTS --')
    

    分号结束插入命令并启动另一个命令; - 评论其余部分 . 执行DROP TABLE命令...

    这就是绑定参数是一件好事的原因 .

  • 69

    单引号是字符串的开头和结尾 . 分号是声明的结尾 . 所以,如果他们正在做这样的选择:

    Select *
    From Students
    Where (Name = '<NameGetsInsertedHere>')
    

    SQL将成为:

    Select *
    From Students
    Where (Name = 'Robert'); DROP TABLE STUDENTS; --')
    --             ^-------------------------------^
    

    在某些系统上,首先运行 select ,然后运行 drop 语句!消息是:不要将值嵌入到您的SQL中 . 而是使用参数!

  • 5

    '); 结束查询,它不会启动注释 . 然后它删除学生表并评论应该执行的查询的其余部分 .

  • 16

    数据库的作者可能做了一个

    sql = "SELECT * FROM STUDENTS WHERE (STUDENT_NAME = '" + student_name + "') AND other stuff";
    execute(sql);
    

    如果给出了student_name,则使用名称“Robert”进行选择,然后删除该表 . “ - ”部分将给定查询的其余部分更改为注释 .

  • 14

    在这种情况下,'不是评论字符 . 它用于分隔字符串文字 . 这位漫画家的想法是,有问题的学校在某个地方有动态的sql,看起来像这样:

    $sql = "INSERT INTO `Students` (FirstName, LastName) VALUES ('" . $fname . "', '" . $lname . "')";
    

    所以现在'字符在程序员期待它之前结束字符串文字 . 结合;要结束语句的字符,攻击者现在可以添加他们想要的任何sql . - 最后的注释是为了确保原始语句中的任何剩余sql不会阻止查询在服务器上进行编译 .

    FWIW,我也认为有问题的漫画有一个重要的细节错误:如果你正在考虑清理你的数据库输入,正如漫画所暗示的那样,你仍然做错了 . 相反,您应该考虑隔离数据库输入,正确的方法是通过参数化查询 .

  • 35

    SQL中的 ' 字符用于字符串常量 . 在这种情况下,它用于结束字符串常量而不用于注释 .

  • 24

    这是它的工作原理:让我们假设管理员正在寻找学生的记录

    Robert'); DROP TABLE STUDENTS; --
    

    由于管理员帐户具有较高权限,因此可以从此帐户中删除该表 .

    从请求中检索用户名的代码是

    现在查询将是这样的(搜索学生表)

    String query="Select * from student where username='"+student_name+"'";
    
    statement.executeQuery(query); //Rest of the code follows
    

    结果查询变为

    Select * from student where username='Robert'); DROP TABLE STUDENTS; --
    

    由于用户输入未被清理,因此上述查询被分为两部分

    Select * from student where username='Robert'); 
    
    DROP TABLE STUDENTS; --
    

    双短划线( - )只会注释掉查询的剩余部分 .

    这很危险,因为它可以使密码验证无效(如果存在)

    第一个将进行正常搜索 .

    如果该帐户具有足够的权限,则第二个将删除该表学生(通常,学校管理员帐户将运行此类查询并且将具有上述权限) .

相关问题