带有验证码的安全保护表格
CAPTCHA实际上是完全自动公开图灵测试的缩写,以区分计算机和人类。该技术与前文介绍的 "用令牌保护表单安全 "中的技术类似。不同的是,该标记不是存储在一个隐藏的表单输入字段中,而是呈现为一个自动攻击系统难以解读的图形。此外,验证码的目的与表单令牌略有不同:它旨在确认网络访问者是人类,而不是自动系统。
如何做...
1.CAPTCHA有几种方法:根据只有人类才会拥有的知识提出问题,文字技巧,以及需要解释的图形图像。
2. 图像方法为网络访问者提供了一个带有严重扭曲的字母和/或数字的图像。然而,这种方法可能很复杂,因为它依赖于GD扩展,而GD扩展可能不是在所有服务器上都能使用。GD扩展可能很难编译,并且严重依赖主机服务器上必须存在的各种库。
3. 文本方法是呈现一系列的字母或数字,并给网络访问者一个简单的指示,如请倒着输入。另一种变化是使用ASCII "艺术 "来形成字符,使人类的网络访问者能够解释。
4. 最后,你可能会有一个问题或答案的方法,问题如The head is attached to the body by what body part,有答案如Arm、Leg、Neck。这种方法的缺点是,自动攻击系统通过测试的几率只有1/3。
生成一个文本验证码
1.在这个例子中,我们将从文本方法开始,然后是图像方法。无论哪种情况,我们首先需要定义一个类来生成短语(并由网络访问者解码)。为此,我们定义了一个Application\Captcha\Phrase类。我们还定义了短语生成过程中使用的属性和类常量。
namespace Application\Captcha;
class Phrase
{
const DEFAULT_LENGTH = 5;
const DEFAULT_NUMBERS = '0123456789';
const DEFAULT_UPPER = 'ABCDEFGHJKLMNOPQRSTUVWXYZ';
const DEFAULT_LOWER = 'abcdefghijklmnopqrstuvwxyz';
const DEFAULT_SPECIAL =
'¬\`|!"£$%^&*()_-+={}[]:;@\'~#<,>.?/|\\';
const DEFAULT_SUPPRESS = ['O','l'];
protected $phrase;
protected $includeNumbers;
protected $includeUpper;
protected $includeLower;
protected $includeSpecial;
protected $otherChars;
protected $suppressChars;
protected $string;
protected $length;2. 正如你所期望的那样,构造函数接受各种属性的值,并分配了默认值,因此无需指定任何参数即可创建实例。$include*标志用于指示哪些字符集将出现在基础字符串中,而短语将从基础字符串中生成。例如,如果你希望只包含数字,$includeUpper和$includeLower都会被设置为FALSE。提供$otherChars是为了增加灵活性。最后,$suppressChars代表一个将从基本字符串中删除的字符数组。默认情况下会删除大写字母O和小写字母l。
3. 然后我们定义了一系列的getter和setter,每个属性一个。请注意,为了节省空间,我们只显示前两个。
4. 接下来我们需要定义一个初始化基础字符串的方法。这由一系列简单的if语句组成,这些语句检查各种$include*标志,并适当地追加到基础字符串中。最后,我们使用str_replace()来删除$suppressChars中代表的字符。
5. 现在我们准备好定义核心方法,生成验证码呈现给网站访问者的随机短语。我们设置一个简单的for()循环,并使用新的PHP 7 random_int()函数在基础字符串中跳转。
6. 现在我们将注意力从短语转移到产生文本验证码的类上。为此,我们首先定义一个接口,以便将来可以创建更多的CAPTCHA类,这些类都可以使用Application\Captcha\Phrase。请注意,getImage()将返回文本、文本艺术或实际图像,这取决于我们决定使用哪个类。
7. 对于文本验证码,我们定义了一个Application\Captcha/Reverse类。之所以叫这个名字,是因为这个类产生的不仅仅是文本,而是反向的文本。__construct()方法建立了一个Phrase的实例。请注意,getImage()返回的是反向的短语。
生成一个图像验证码
1.形象的方法,你可以很好地想象,要复杂得多。短语的生成过程是一样的。主要的区别是,我们不仅需要将短语印在图形上,还需要对每个字母进行不同的变形,并以随机点的形式引入噪声。
2. 我们定义了一个Application\Captcha\Image类,实现了验证码接口。该类的常量和属性不仅包括生成短语所需要的,还包括生成图像所需要的。
3. 构造函数需要接受所有生成短语所需的参数,如前几步所述。此外,我们还需要接受生成图像所需的参数。两个必选参数是$imageDir和$imageUrl。第一个是图形将被写入的地方。第二个是基础URL,之后我们将附加生成的文件名。提供$imageFont是为了防止我们提供TrueType字体,这将产生一个更安全的验证码。否则,我们只能使用默认字体,引用著名电影中的一句台词,这可不是什么好事。
4. 接下来,仍然在构造函数中,我们检查 imagecreatetruecolor 函数是否存在。如果返回的是false`,我们就知道GD扩展不可用。否则,我们为属性分配参数,生成短语,删除旧图片,写出验证码图形。
5. 删除旧图片的过程是极其重要的,否则我们最终会发现目录中充满了过期的验证码图片!我们使用DirectoryIterator类扫描指定的目录,并检查访问时间。我们使用DirectoryIterator类来扫描指定的目录并检查访问时间。我们计算一个旧的图像文件是当前时间减去IMAGE_EXP_TIME指定的值。
6. 我们现在准备好进入正题。首先,我们将$imageRGB数组分割成$red、$green和$blue。我们使用核心的imagecreatetruecolor()函数来生成指定宽度和高度的基础图形。我们使用RGB值对背景进行着色。
7. 接下来,我们根据图像的宽度和高度定义x和y边距。然后我们初始化变量,用于将短语写到图形上。然后,我们循环次数与短语的长度相匹配。
8. 如果指定了$imageFont,我们就能够用不同的大小和角度来书写每个字符。我们还需要根据大小调整x轴(即水平)值。
9. 否则,我们就只能使用默认字体。我们使用最大的5号字体,因为较小的字体是不可读的。我们通过交替使用imagechar()和imagecharup()来提供低水平的失真,imagechar()可以正常写入图像,而imagecharup()可以横向写入图像。
10. 接下来我们需要以随机点的形式添加噪声。这是必要的,以便使图像更难被自动系统检测到。同时建议你也添加代码来画几条线。
11. 然后,我们使用我们的老朋友md5()创建一个随机的图像文件名,参数为日期和一个0到9999的随机数。请注意,我们可以安全地使用md5(),因为我们并没有试图隐藏任何秘密信息;我们只是想快速生成一个唯一的文件名。为了节省内存,我们也擦掉了图像对象。
12. 整个构造都在try/catch块中。如果出现错误或异常,我们会记录消息并采取适当的行动。
13. 最后,我们定义接口所需的方法。注意,getImage()会返回一个HTML <img>标签,然后可以立即显示。
如何运行...
一定要定义本事例中所讨论的类,总结在下表中。
Class
小节
出现步骤
Application\Captcha\Phrase
Generating a text CAPTCHA
1 - 5
Application\Captcha\CaptchaInterface
6
Application\Captcha\Reverse
7
Application\Captcha\Image
Generating an image CAPTCHA
2 - 13
接下来,定义一个名为chap_12_captcha_text.php的调用程序,实现文本验证码。你首先需要设置自动加载并使用相应的类。
之后,一定要开始会话。你也会使用适当的措施来保护会话。为了节省空间,我们只展示一个简单的措施,session_regenerate_id()。
接下来,你可以定义一个创建验证码的函数;检索短语、标签和图像(在本例中,反向文本);并将值存储在会话中。
现在是初始化变量和确定登录状态的好时机。
然后,您可以检查是否已按下登录按钮。如果是,检查是否输入了验证码短语。如果没有,则初始化一条消息,通知用户他们需要输入验证码短语。
如果存在验证码短语,检查它是否与会话中存储的内容相匹配。如果不匹配,则继续进行表单无效的处理。否则,按照其他方式处理登录。在本例中,您可以使用硬编码的用户名和密码来模拟登录。
你可能还想添加注销选项的代码,就像保护PHP会话事例中描述的那样。
然后你可以运行setCaptcha()。
最后,别忘了视图逻辑,在这个例子中,呈现的是一个基本的登录表单。在表单标签里面,你需要添加视图逻辑来显示验证码和标签。
下面是结果输出。

为了演示如何使用图片验证码,请将chap_12_captcha_text.php中的代码复制到cha_12_captcha_image.php中。我们定义了常量来表示验证码图片的目录位置. (一定要创建这个目录!)否则,自动加载和使用语句的结构是相似的。注意,我们还定义了一个TrueType字体。不同之处用粗体表示。
字体可能受到版权、商标、专利或其他知识产权法律的保护。如果您使用的字体没有得到授权,您和您的客户可能会被追究法律责任。使用开放源码的字体,或者是在网络服务器上可以使用的字体,你得有一个有效的许可证。
当然,在setCaptcha()函数中,我们使用Image类代替Reverse。
变量初始化与上一个脚本相同,登录处理与上一个脚本相同。
即使是视图逻辑也是一样的,因为我们使用的是getImage(),在图片验证码的情况下,它直接返回可用的HTML。下面是使用TrueType字体的输出。

更多...
如果你不愿意使用前面的代码来生成自己的内部验证码,有很多库可以使用。大多数流行的框架都有这种能力。例如,Zend Framework有其Zend\Captcha组件类。还有reCAPTCHA,它通常是作为一个服务调用的,在这个服务中,你的应用程序调用一个外部网站,这个网站为你生成验证码和令牌。一个好的地方是http://www.captcha.net/ 网站。
关于将字体作为知识产权加以保护的更多信息,请参阅https://en.wikipedia.org/wiki/Intellectual_property_protection_of_typefaces。
最后更新于