天天看點

c#實作簡單Token密碼驗證

  最近一個項目發現手機驗證碼總是被人盜刷,一秒鐘刷了1百多個,很明顯這種行為是通過軟體自動送出的,自動發帖機原理類似,解決這個問題目前有兩個方案。

  出現這個問題原因:請求手機驗證碼Api時沒有任何帶任何驗證,隻要請求了手機号正确就執行發送操作,軟體或代碼很容易僞造請求過程。

  解決方案有很多種,可以選擇下面一種或幾種組合起來使用。

  方案1:使用者擷取手機驗證碼時候彈出圖檔驗證碼,輸入後再發送。

  優點:增加僞造請求成功的難度,必須輸入驗證碼才可以發送,如果是軟體,軟體需要有圖檔驗證碼識别功能。

  缺點:使用者體驗不好,增加了普通使用者的操作步驟。

  方案2:增加ip黑名單,即檢測請求ip的發送頻率,如同一個ip一分鐘内請求多少次後屏蔽ip。

  缺點:一些軟體有主動更換ip的功能,這種方式效果不是很好。

  方案3:加上token密碼驗證

  在Api中增加密碼驗證,即每次請求必須帶上token,token驗證正确了才執行發送操作。

  這個方案為了替代方案1,因為有的公司對前端體驗要求極高,增加使用者操作步驟後使用者體驗不好。

  這裡token可以放在資料庫中,也可以放在記憶體中,個人建議放在記憶體中,速度快,查詢快,至于備援的問題,可以增加一個BuildDate來儲存生成時間。

  Token描述類

  public class TokenDescriptor

  {

  ///

  /// 用戶端唯一Id,必須保證唯一性

  public string ClientId { get; set; }

  /// token

  public string Token { get; set; }

  /// token生成日期

  public DateTime BuildDate { get; set; }

  }

  token處理類

  public class TokenFactoryBLL

  private string _ClientId;

  private static List _TokenList;

  static TokenFactoryBLL()

  _TokenList=new List();

  public TokenFactoryBLL(HttpRequestBase httpRequestBase)

  _ClientId=StringHelper.ClientId(httpRequestBase);

  ClearExpired();

  /// 可用于遠端api

  public TokenFactoryBLL(string clientId)

  _ClientId=clientId;

  /// 生成密碼

  public string Get()

  if (string.IsNullOrEmpty(_ClientId))

  return null;

  string token=Guid.NewGuid().ToString("N");//guid;

  TokenDescriptor tokenDescriptor=new TokenDescriptor();

  tokenDescriptor.ClientId=_ClientId;

  tokenDescriptor.Token=StringHelper.NewGuid();

  tokenDescriptor.BuildDate=Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

  _TokenList.Add(tokenDescriptor);

  return token;

  /// 驗證token

  public TipsInfo Validate(string token)

  TipsInfo tipsInfo=new TipsInfo();

  if (!_TokenList.Exists(c=> c.ClientId.Equals(_ClientId, StringComparison.OrdinalIgnoreCase) && c.Token.Equals(token, StringComparison.OrdinalIgnoreCase)))

  tipsInfo.State=0;

  tipsInfo.Msg="token密碼驗證失敗";

  return tipsInfo;

  /// 移除對應用戶端的所有token

  public void Remove()

  _TokenList.RemoveAll(c=> c.ClientId.Equals(_ClientId, StringComparison.OrdinalIgnoreCase));

  /// 清理過期的token,過期時間10分鐘

  private static void ClearExpired()

  for (var i=0; i < _TokenList.Count; i++)

  TokenDescriptor item=_TokenList[i];

  DateTime startTime=item.BuildDate;

  DateTime endTime=Convert.ToDateTime(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));

  TimeSpan ts=endTime - startTime;

  int minutes=ts.Minutes;

  if (minutes>10)

  _TokenList.RemoveAt(i);

  附上Helper工具類中clientId的方法:

  /// 擷取并生成用戶端唯一Id,儲存在cookie中;

  public static string ClientId(HttpRequestBase request) //擷取用戶端唯一Id

  if (request==null)

  string clientId=CookieHelper.Get("_clientId_");

  if (string.IsNullOrEmpty(clientId))

  string guid=Guid.NewGuid().ToString("N");//guid

  string ip=StringHelper.GetClientIP().ToString().Replace(".", "").Replace(":", "");

  clientId=guid + ip;

  CookieHelper.Add("_clientId_", clientId);

  return clientId;

  /// 擷取用戶端ip

  public static string GetClientIP()

  if (System.Web.HttpContext.Current==null) return "127.0.0.1";

  string clientIp=System.Web.HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"];

  if (string.IsNullOrEmpty(clientIp))

  clientIp=System.Web.HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];

  clientIp=System.Web.HttpContext.Current.Request.UserHostAddress;

  if (clientIp.IndexOf(",") > 0)

  clientIp=clientIp.Split(',')[0];

  if (!StringHelper.IsIp(clientIp))

  clientIp="127.0.0.1";

  return clientIp;

  前端發送方式需要更改,在請求手機驗證碼的api之前,先第一次請求

二手QQ賣号平台

擷取token,然後帶上token驗證通過後後再請求api。

  這個方案肯定沒有驗證碼的防護效果好,隻是增加了僞造請求的步驟,因為現在很多模拟請求的軟體都是一次性請求,是以還是能防護大部分的軟體。