就在工行网络系统瘫痪同一周,自己在17173参与的第二个项目——新版通行证上线了。

通行证改造项目涉及到比较多的表单验证。表单是用户与网站交互的主要途径, 做好这一环节体验的重要性不言自明。 拿现实生活中的场景举例, 顾客在商场购物前往往会通过与导购间的交流来确认自己是否需要该商品。 如果遇到冷淡无礼 对售前咨询不耐烦的导购, 一桩买卖可能就这么黄了。 而设计糟糕的表单就像无礼的导购—— 对用户辛辛苦苦完成的表单粗暴地返回“信息有误” 或者“请稍候再试”提示的表单容易让人产生挫败感, 无形中造成用户流失。

自己以往接触过的项目为图省事采用的都是表单提交前检测。而新版通行证项目选用jQuery.validation 插件实现实时检测。好在插件提供的接口灵活, 定制性高, 适用场景比较广, 足以应对 项目中遇到的各种场景。

印象中第一次接触实时表单验证是在09年注册Twitter 帐号时, 感觉和以往的注册体验不同, 整个注册流程像是一场对话, 自己的每一个输入都能立马得到响应, 让人知道自己是在往正确的方向完成表单。

Every coin has two sides, 实时检测运用得当能够提升体验, 运用不当反而造成困惑。拿项目中出问题较多的两个部分来说

一、提示信息

提示信息应该在适当的位置适时出现

新版通行证表单的提示信息一般都位于输入字段的旁边, 如果表单中含有错误项, 用户很容易就能够定位到需要修改的字段;
在用户输入的过程中更新提示信息, 引导用户修正输入, 最终完成符合要求的表单。

提示信息除了判断输入是否符合要求外, 最好能给出不通过的原因及修改建议, 同时避免出现术语

比如提示用户昵称已被使用时, 可以同时推荐可用昵称;
再比如提示注册邮箱已使用时, 可能用户未意识到自己曾经注册过17173 通行证, 此时用户也许更需要的是重置密码的链接。

二、检测方法

项目中的检测主要分三类:

  1. 格式检测如用户名非空、Email格式验证;
  2. 输入值检测,预期输入值唯一,非等既不通过。如验证码、密保问题的前端验证部分;
  3. 远程数据查询,如帐号是否可注册(未被抢注),需要将用户的输入传到数据库进行查询才能确定输入是否有效。

第一类最简单, 可通过特定的检测方法(由检测规则抽象而来的函数)在浏览器端完成验证;

第二类这里的处理方式是将预期值在服务端处理过(如:验证码检测是将验证码的每一位取ascii码求和)的特征值作为输入项的属性(input[data-cipher])随网页传送到浏览器端,验证时将输入值经过相同算法处理的结果与特征值进行比对。

由于特征值只包含正确答案的部分信息,恶意用户即使知道特征值的加密方法(JS函数)也无法进行反向求解获取正确答案。也由于特征值只包含部分信息,存在特征值碰撞的情况,比如注册表单的验证码乱序输入也能通过前端检测(虽然还是无法通过服务端验证)。所以这种方法只适用于以提升用户体验为目的的 非安全输入项的前端检测。

第三类相对复杂,在验证时发送请求, 根据服务器返回信息对用户进行提示。 这里遇到的问题是:如果使用异步请求, 则如果表单中存在多个需远程比对的检测项时, 在表单提交前触发的验证(除了输入项检测,插件还会在表单提交前对整个表单进行检测)会由于多个请求返回的响应间存在时差,导致已有提示信息的闪动。目前采用同步请求的临时方案,为了避免频繁发送同步请求导致卡顿,只在输入框失去焦点是触发远程检测。

Upadate 130924:

悲剧的173生涯首次迟到的一天… 上午收到白帽通知, 原先自鸣得意的特征值前端验证方法(检测方法-第二类)间接导致了一次攻击的实现。

大致情况是一位论坛管理员密保问题被通过社工手段破解,攻击者得以重置密码获得论坛管理员权限。虽然部分原因是被攻击帐号安全问题过于简单(常用Q号),但前端检测功能还是让攻击者得以无限试错,降低了攻击成本。目前已改用后端验证输入,试错一定次数冻结密保问题找回密码功能24小时的策略。

这个问题被暴露中得到的教训是不能单纯的从技术角度来考虑问题——通过特征值反向求解得出密保问题答案固然小概率, 但配合社会工程手段,安全策略被绕过可能性的增长就会超乎预料。譬如QQ号一般人常用的不会超过3个,这样答案被反向求解的概率分母就不是5-11位数字的组合,而很可能是N(常用的N个QQ号都被搜到)。

在不确定身处蛮夷还是乐园的时候,不妨假设面临的是最糟的情况而不是盲目乐观。掌握了在互联网丛林暗黑地带求生的本领,才开始具备谈论改进用户体验的资格,在此前提下提出的改进创意才有意义。