科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网安全频道应用安全小心你的WEB应用程序成为数据窃贼的帮凶(三)

小心你的WEB应用程序成为数据窃贼的帮凶(三)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

在前两部分文章中,我们介绍了攻击者如何通过SQL注入攻击来利用Web应用程序的漏洞以及SQL注入攻击的方法。本文我们将介绍抵御该攻击的措施之一:保证应用程序编码的安全。

来源:TechTarget中国 2011年9月30日

关键字: 数据泄漏 Web应用安全

  • 评论
  • 分享微博
  • 分享邮件

  在(一)(二)前两部分文章中,我们介绍了攻击者如何通过SQL注入攻击来利用Web应用程序的漏洞以及SQL注入攻击的方法。本文我们将介绍抵御该攻击的措施。

  防御措施:保证应用程序编码的安全

  安全的编码技术可以清除造成SQL注入攻击的漏洞。下面说的是Web应用程序安全编码的三个基本方法。

  方法一:输入验证

  在Web应用程序这一层防止SQL注入最常见的方法是使用输入验证。无论是何种语言或平台,这种方法都很有用。其实质就是在验证用户输入的大小和类型前,不对其采取行动。如果你期望用户输入的是数字,就不要接受非数字的东西。

  例如,下面的URL:

  wangzhan.com/userdetail.asp?userid=9899

  很明显,在这个GET请求中,我们期望输入一个整数。一个简单的类型检查会告诉我们这是不是一个合法的字符,从而确保应用程序不会处理非数字值的输入。

  if (is_numeric($userid)){}

  此外,如果用户的ID总是四个字符的长度,我们就可以进一步采取措施,除了使用常规的表达式来执行整型检查,还可以强化边界检查。

  if (preg_match(‘\d{4}’, $string)) {}

  在对待如何验证用户输入值的这个问题上,我们仅受到自己创造力的限制。这里的关键是验证由用户发送并由系统使用的每一个值。

  执行类型检查的另外一种方法是通过ASCII字符。用户名一般是由字母和数字组成的,所以我们不希望看到类似“@”、“;”之类的字符。因而,我们可以解析用户名变量,看看是否存在着不属于48-57,65-90,97-122的任何ASCII字符。在这个范围之外的任何ASCII字符对于用户名变量来说,都是不合法的,应当拒绝接受。这就是所谓白名单的一个例子。

  知道白名单和黑名单的区别非常重要。白名单仅接受已知为安全的值或字符,如字母和数字。而黑名单则会阻止或不接受已知为恶意的字符。

  方法二:规避技术

  到目前为止,类型检查和边界检查似乎很容易,但并非在检查所有的数据类型时都会这么简单。许多情况下,我们还会使用VARCHAR数据类型(VARCHAR是一种比CHAR更加灵活的数据类型,同样用于表示字符数据,但是VARCHAR可以保存可变长度的字符串。)此类型有可能包含危险字符。这在备注字段和其它的长表单文本字段中很常见。

  在这种情况下,我们可以利用一种称为规避的技术来确保变量的内容绝对不会被解析为SQL语句的一部分。

  请看下面这个例子中的请求:

  wangzhan.com/comment.asp?msg=I’m zhangsan.

  在这个例子中,有一个撇号(’),这是一种常被认为是恶意字符的字符(请参考上一篇文章提到的撇号),我们并不希望排除它,因为此处它的用法是合法的,我们也不希望拒绝这个消息。

  例如,在PHP中,我们可以使用mysql_real_escape_string函数:

  mysql_real_escape_string($GET[‘msg’]);

  这就不会导致安全问题,而是安全地解决了撇号问题,使其不能用于任何MySQL查询中:

  msg=“Hello I\’m zhangsan”

  同样地,在微软的.NET架构中,设计者常用REPLACE来保证字符串的安全。在下面的例子中,REPLACE函数将撇号(’)放在引号中,使其成为一种安全字符:

  sql = replace(str, “’“, “’“)

  方法三:参数化查询

  防止SQL注入的第三种方法是一种称为参数化查询的技术。这种方法非常有效,因为它可以非常严密地控制SQL语句的组成结构。此方法在将对SQL语句的任何重要变更交给SQL服务器处理之前就拒绝其操作。

  下面的Java例子中,我们简单地将参数添加到已经构建的静态查询中。首先,我们使用问号作为变量建立了真实的SELECT语句:

  String query = “SELECT account_balance FROM user_data WHERE user_name = ? “;

  下一步,我们调用prepareStatement函数:

  PreparedStatement pstmt = connection.prepareStatement( query );

  然后,在查询中我们将字符串“custname”指派给变量:

  pstmt.setString( 1, custname);

  最后,我们执行查询,并将结果存储在一个变量中:

  ResultSet results = pstmt.executeQuery( );

  通过使用这种方法,我们能够确保在附加的恶意查询或参数被发送给数据库之前,不会被添加到查询中。注意,应当像前面所讨论的那样来验证“custname”变量,因为它是不受信任的用户输入。

  在下一篇文章中,我们将讨论另外一种策略:使用存储SQL过程。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章