Heero's Blog

Heero's Blog » ASP.NET/C#

验证码的几个常见漏洞

把验证码存储在Cookie中

一般来说,我们会把验证码的值用Session存储起来,通过对比用户提交的验证码和Session中的验证码,就可以知道输入是否正确。由于Session会占用服务器资源,我曾经想过是否可以把验证码的值加密后存储在Cookie中。不过事实证明,这只是异想天开罢了。

假设验证码的值是a,通过sha1加密后得到的值为b = sha1(a),并且把b存储在Cookie中。而用户提交的验证码值为c,通过判断sha1(c)是否与b相等,可以知道输入的验证码是否正确。然而,Cookie是受客户端控制的。如果用户事先通过肉眼看到验证码的值是a,又从Cookie中得知此时的加密值为b,那么,他只要在提交前把Cookie的值修改为b,提交的验证码值为a,就可以永远通过验证。

没有进行非空判断

这种情况可以直接用代码来说明:

if (Request["captcha"] == Session["captcha"] as string)
{
    // 验证通过,继续操作
}

假设用户绕过了系统提供的

使用页面代理调用网易微博数据

由于网易微博的数据还没有完全对外开放,像“我的首页”、“我的微博”的JSON数据都不能直接通过Javascript调用,而是必须先登录才能获取。因此,要想把微博数据调用到博客上,就得在后台做一个页面代理

页面代理的唯一工作就是带上已登录的Cookie发送一个Http请求,获取并输出回应内容。这个过程主要涉及到两个类,HttpWebRequestHttpWebResponse,它们都在System.Net名字空间内。

通过Firebug的网络面板可以看到,网易微博中“我的微博”数据地址如下:

http://t.163.com/statuses/user_timeline/用户名.json

先建立一个HttpWebRequest类的实例,并设置相应属性的值:

HttpWebRequest request = (HttpWebRequest)HttpW

从表单数据创建实体对象

Web应用的基本流程就是通过表单提交数据到服务器,服务器端程序以这些数据建立实体对象,经过处理后更新到数据库。而从表单数据创建实体对象的过程通常是很麻烦的,必须考虑到以下几点:

  1. 创建什么类型的对象?
  2. 表单的各项数据如何映射到对象的各项属性?
  3. 提交到服务器的数据都是字符串类型的,要还原成对应属性的数据类型。

之前我就用泛型写了一个Request工具类。不过这个类仅仅是解决了第三个问题而已,而要解决前两个问题就得靠反射了。

要解决第一个问题,还得用泛型,也就是类型作为参数传入,由此得到这个通用函数的原型:

public class ReqHelper
{
  public static T GetEntity<T>()
  {

使用泛型打造Request工具类

在ASP.NET页面中可以使用Request对象获取指定参数的值,例如:

string value = Request["id"];

参数值都是string类型,但是进行处理的时候可能要转换成数字、日期等类型。

string value = Request["id"];
int id = Int32.Parse(value);

实际应用的时候还要考虑异常的情况。

string value = Request["id"];
int id;
Int32.TryParse(value, out id);

如果每个页面都这么写,显得非常麻烦,代码重复也很严重,还是封装成一个工具类吧。

public class ReqHelper
{
  public static string Get

使用JavaScriptSerializer进行JSON序列化

JSON是Javascript中常用的数据格式,然而,在.NET 2.0中没有内置序列化JSON的类,原因估计是当时Ajax尚未兴起。后来就有人写了一个Json.NET类库。.NET 3.5新增了一个把对象序列化为JSON字符串的类JavaScriptSerializer。这个类位于System.Web.Script.Serialization名字空间中(非Web项目需要添加System.Web.Extensions.dll引用),其使用方法也是非常简单的:

// 分类
public class Category
{
  public int CategoryId { get; set; } // 分类编号
  public string CategoryName { get; set; } // 分类名