关于实现验证码需要注意的问题

缘起:

如果能在用户输入验证码后就知道输入是否正确的话,用户体验会好很多,而且对于难以识别的验证码还能给用户重新输入的机会。【后来才发现,允许重新尝试同一个验证码本身就是有安全问题的

思考:

方案1: 验证码不和真实业务数据一起提交的话,而是验证码先提交,如果验证码正确则换取一张有效的凭证,然后将凭证和真实业务数据一起提交;否则刷新验证码(安全考虑,验证码必须验证一次后失效),重新输入

方案2: 生成验证码图片的时候,将验证码的hash值返回给用户端,这样,用户输入验证码后,通过js来比较hash值,就可以在很大程度上预判验证码的正确性了,因为同一个验证码可以尝试多次(这本身就是个漏洞)。

安全方面的考虑:

  1. 如果hash值是对验证码直接做的hash,则:
    1) 可以生成一个足够大的hash值的数据库,直接根据hash值反解出验证码
    2) 图片验证码的识别技术 + 根据hash值的进一步校验,使得验证码的破解成功率大大提高
    3) 可能有一个足够强大的计算平台,根据一定的规则反解hash值
  2. 或许可以对验证码和一个临时的随机串来一起来做hash值,如此,则:
    1) 图片验证码的识别技术 + 根据hash值的进一步校验,使得验证码的破解成功率大大提高
    3)   可能有一个足够强大的计算平台,根据一定的规则反解hash值
  3. 理论上来讲,验证码必须只能验证一次后失效,否则:
    1) 图片验证码的识别技术 + 根据hash值的进一步校验,使得验证码的破解成功率大大提高

 结论:

方案1 基本可行,但是要对验证码的尝试做IP封禁策略

方案2 对于不太关键的业务或许可以临时用一下

 

验证码服务模型

1. 一个输出验证码的接口,同时输出验证码的id

2. 一个验证验证码的接口,可能会输出验证成功的票据(票据是一次性的)

3. 一个验证票据的接口

 

票据的引入为了处理这种情况: 提交的数据量比较大,如果提交后报告验证码错误,显得很没有效率;这种情况,就可以先验证验证码,验证码成功后再提交数据,但是需要借助票据来实现

 

母亲我叫钓鱼岛

母亲我叫钓鱼岛
七百年前你起的名字植入我的襁褓
我徜佯在你温暖的怀抱
从此我不再是无根的水草
母亲我叫钓鱼岛
一百年前的马关火炮
撕裂我伤痕累累的骄傲
我在你的眼眸里云散烟消
那些年你可知道
我飘摇的心多么需要依靠
母亲我叫钓鱼岛
六十年前你轻轻把我的名字呼叫
我的欣喜被阳光照耀
可是强盗在最后时刻强行夺去了我的贞操
那一刻,母亲你可知道
我屈耻地活着水深火热地煎熬
母亲我叫钓鱼岛
三十年前强盗在我的身躯上修起了跑道
他们想要掠夺我
全部的妖娆
我不应该是强盗餐桌上的佳肴
我的呐喊母亲你可听到
母亲我叫钓鱼岛
二十年前强盗在我的身躯上让灯塔闪耀
他们想要占有我的身体到天荒地老
我不应该是强盗无耻的夜宵

我支离破碎的容貌母亲你可看到
母亲我叫钓鱼岛
不是强盗嘴里的尖阁列岛
我不应该背着沉重的背包
在尘世的纷纷扰扰中被人嘲笑
我的精彩应该闪
耀在你博大的云霄
我的骄傲应该执着在你温暖的怀抱
母亲我叫钓鱼岛
我期待期待那一秒
您披起战袍吹响号角
在犀利的炮火中将我的名字呼叫
那一刻母亲
躺在你温柔怀中我是您永远要呵护的宝
母亲我叫钓鱼岛

顺序读写与随机读写

对于同一个文件,虽然每次读写的数据量很小,但是如果每次读写的位置很随机,那么读写的效率也是很低的,大家都知道。

但是有一种情况,可能不太被注意,虽然是顺序读写,依然很慢;现在有一个进程顺序写一个文件,可能每秒能写100多MB,但是,如果有100个类似的进程顺序写100个不同的文件,虽然表面上都是在顺序写,但是对于磁盘来讲,需要不断地切换磁头到不同的文件,其实也已经表现为随机写了。

 

bash 基础

一些小的知识点:
  1.  ‘(‘,’)’ 是元字符, ‘{‘,’}’ 是保留字,所以圆括号两边可以没有空格,而花括号两边必须有空格
  2. ((expression))  是一个算数表达式;  [[ expression ]] 是一个条件表达式
  3. &>word     >&word 都等价于 >word 2>&1 ; 推 荐 使 用 第 一 种
  4. 将 字 符 放 在 单 引 号 之 中 , 将 保 留 引 用 中 所 有 字 符 的 字 面 意 义 。 单 引 号 不 能 包 含 在 单 引 号 引 用 之 中 , 即 使 前 面 加 上 了 反 斜 杠
  5. 将 字 符 放 在 双 引 号 中 , 同 样 保 留 所 有 字 符 的 字 面 意 义 , 例 外 的 情 况 是 $, 和\。 字 符 $ 和  在 双 引 号 中 仍 然 具 有 特 殊 意 义 。 反 斜 杠 只 有 后 面 是 下 列 字 符 时 才 有 特 殊 意 义 : $\, 或 <newline>. 双 引 号 可 以 包 含 在 双 引 号 引 用 中 , 但 要 在 前 面 加 上 一 个 反 斜 杠
  6. 双 引 号 引 用 字 符 串 前 面 加 上 一 个 $ 符 号 将 使 得 这 个 字 符 串 被 根 据 当 前 语 言 环 境 (locale) 来 翻 译
  7. getopts 是一个内建命令

 

练习

for (( expr1 ; expr2 ; expr3 )) ; do list ; done

for name [ in word ] ; do list ; done

select name [ in word ] ; do list ; done

case word in [ [(] pattern [ | pattern ] … ) list ;; ] … esac

 

圆括号的用法

  1. 子shell:

    命令在子shell中执行,不影响当前shell环境,当前shell的当前环境不发生变化
  2. 子shell求值

    ls 的结果赋值给files变量
  3. 算术表达式

    注意: 不能写作: (($i++)),因为如果i=1,替换之后为((1++)) ,显然没法运算,但是:
  4. 数组

    arr是个数组,包含当前目录下面的所有文件名

    str 是个字符串

    arr是一个包含字符串ls的数组
  5. 字符串替换

    注意: 该特性在 GNU bash,版本 4.4.19(1)-release (x86_64-pc-linux-gnu) 上测试通过,在 GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) 上测试不通过

fork() vs vfork()

摘自: http://tldp.org/HOWTO/Secure-Programs-HOWTO/avoid-vfork.html

The portable way to create new processes in Unix-like systems is to use the fork(2) call. BSD introduced a variant called vfork(2) as an optimization technique. In vfork(2), unlike fork(2), the child borrows the parent’s memory and thread of control until a call to execve(2V) or an exit occurs; the parent process is suspended while the child is using its resources. The rationale is that in old BSD systems, fork(2) would actually cause memory to be copied while vfork(2) would not. Linux never had this problem; because Linux used copy-on-write semantics internally, Linux only copies pages when they changed (actually, there are still some tables that have to be copied; in most circumstances their overhead is not significant). Nevertheless, since some programs depend on vfork(2), recently Linux implemented the BSD vfork(2) semantics (previously vfork(2) had been an alias for fork(2)).

翻译:

在类Unix系统中, 可移植的创建一个新进程的方式是调用fork(2)。BSD中作为一种优化技术引入了一个叫做vfork(2) 的变体。vfork(2) 和fork(2) 不同,它在退出或者调用execve(2V)之前是作为父进程的一个线程存在的,和父进程共用内存空间;而在子进程使用这些资源时,父进程是被挂起的。之所以会有vfork(2),是因为在老的BSD系统中,fork(2)将导致一次真实的内存拷贝,而vfork(2)则不会。Linux中从来没有过这个问题;因为,Linux内部使用的是写时复制(copy-on-write)的机制,Linux仅仅在页被修改时才复制(事实上,仍然会有一些表被复制;在大多数情况下,这没有太大影响)。然而,因为一些程序依赖了vfork(2),最近Linux也实现了BSD的vfork(2)机制(以前的vfork(2)是fork(2)的别名)。

There are a number of problems with vfork(2). From a portability point-of-view, the problem with vfork(2) is that it’s actually fairly tricky for a process to not interfere with its parent, especially in high-level languages. The not interfering” requirement applies to the actual machine code generated, and many compilers generate hidden temporaries and other code structures that cause unintended interference. The result: programs using vfork(2) can easily fail when the code changes or even when compiler versions change.

For secure programs it gets worse on Linux systems, because Linux (at least 2.2 versions through 2.2.17) is vulnerable to a race condition in vfork()’s implementation. If a privileged process uses a vfork(2)/execve(2) pair in Linux to execute user commands, there’s a race condition while the child process is already running as the user’s UID, but hasnt entered execve(2) yet. The user may be able to send signals, including SIGSTOP, to this process. Due to the semantics of vfork(2), the privileged parent process would then be blocked as well. As a result, an unprivileged process could cause the privileged process to halt, resulting in a denial-of-service of the privileged process' service. FreeBSD and OpenBSD, at least, have code to specifically deal with this case, so to my knowledge they are not vulnerable to this problem. My thanks to Solar Designer, who noted and documented this problem in Linux on the `security-audit” mailing list on October 7, 2000.

The bottom line with vfork(2) is simple: don’t use vfork(2) in your programs. This shouldn’t be difficult; the primary use of vfork(2) is to support old programs that needed vfork’s semantics.

 

其它参考: http://linux.about.com/library/cmd/blcmdl2_vfork.htm

 

重点:

1. fork不会挂起父进程, vfork会挂起父进程,直到调用execve或_exit

2. 一般来讲,vfork都是会和execve成对出现的

3. vfork中不应该调用exit

4. 当一个特权进程使用vfork来派生一个非特权进程时,在vfork设置为非特权进程之后,调用execve之前,非特权用户给该进程发送一个STOP信号,将可能会挂起特权进程,所以,尽量不要使用vfork