安全(Security)

该组件可以帮助开发人员在共同安全方面的一些工作,比如密码散列和跨站点请求伪造(CSRF)保护。

密码散列(Password Hashing)

将密码以纯文本方式保存是一个糟糕的安全实践。任何可以访问数据库的人可立即访问所有用户账户,因此能够从事未经授权的活动。为解决这个问题,许多应用程序使用熟悉的 单向散列方法比如”md5“和”sha1“。然而,硬件每天都在发展,变得更快,这些算法在蛮力攻击面前变得脆弱不堪。这些攻击也被称为“彩虹表(rainbow tables )。

为了解决这个问题我们可以使用哈希算法 bcrypt。为什么 bcrypt? 由于其”Eksblowfish“键设置算法,我们可以使密码加密如同我们想要的”慢”。慢的算法使计算 Hash背后的真实密码的过程非常困难甚至不可能。这可以在一个很长一段时间内免遭可能的彩虹表攻击。

这个组件使您能够以一个简单的方法使用该算法:

  1. <?php
  2. use Phalcon\Mvc\Controller;
  3. class UsersController extends Controller
  4. {
  5. public function registerAction()
  6. {
  7. $user = new Users();
  8. $login = $this->request->getPost("login");
  9. $password = $this->request->getPost("password");
  10. $user->login = $login;
  11. // Store the password hashed
  12. $user->password = $this->security->hash($password);
  13. $user->save();
  14. }
  15. }

我们保存一个用默认因子散列的密码。更高的因子可以使密码更加可靠。我们可以用如下的方法检查密码是否正确:

  1. <?php
  2. use Phalcon\Mvc\Controller;
  3. class SessionController extends Controller
  4. {
  5. public function loginAction()
  6. {
  7. $login = $this->request->getPost("login");
  8. $password = $this->request->getPost("password");
  9. $user = Users::findFirstByLogin($login);
  10. if ($user) {
  11. if ($this->security->checkHash($password, $user->password)) {
  12. // The password is valid
  13. }
  14. } else {
  15. // To protect against timing attacks. Regardless of whether a user exists or not, the script will take roughly the same amount as it will always be computing a hash.
  16. $this->security->hash(rand());
  17. }
  18. // The validation has failed
  19. }
  20. }

Salt使用PHP的 openssl_random_pseudo_bytes 函数的伪随机字节生成的,所以需要加载扩展 openssl

防止跨站点请求伪造攻击(Cross-Site Request Forgery (CSRF) protection)

这是另一个常见的web站点和应用程序攻击。如用户注册或添加注释的这类表单就很容易受到这种攻击。

可以想到的方式防止表单值发送自外部应用程序。为了解决这个问题,我们为每个表单生成一个一次性随机令牌(random nonce),在会话中添加令牌,然后一旦表单数据提交到 程序之后,将提交的数据中的的令牌和存储在会中的令牌进行比较,来验证是否合法。

  1. <?php echo Tag::form('session/login') ?>
  2. <!-- Login and password inputs ... -->
  3. <input type="hidden" name="<?php echo $this->security->getTokenKey() ?>"
  4. value="<?php echo $this->security->getToken() ?>"/>
  5. </form>

在控制器的动作中可以检查CSRF令牌是否有效:

  1. <?php
  2. use Phalcon\Mvc\Controller;
  3. class SessionController extends Controller
  4. {
  5. public function loginAction()
  6. {
  7. if ($this->request->isPost()) {
  8. if ($this->security->checkToken()) {
  9. // The token is OK
  10. }
  11. }
  12. }
  13. }

记得添加一个会话适配器到依赖注入器中,否则令牌检查是行不通的:

  1. <?php
  2. $di->setShared(
  3. "session",
  4. function () {
  5. $session = new \Phalcon\Session\Adapter\Files();
  6. $session->start();
  7. return $session;
  8. }
  9. );

同时也建议为表单添加一个 captcha ,以完全避免这种攻击的风险。

设置组件(Setting up the component)

该组件自动在服务容器中注册为“security”,你亦可以重新注册它并为它设置参数:

  1. <?php
  2. use Phalcon\Security;
  3. $di->set(
  4. "security",
  5. function () {
  6. $security = new Security();
  7. // Set the password hashing factor to 12 rounds
  8. $security->setWorkFactor(12);
  9. return $security;
  10. },
  11. true
  12. );

Random

The Phalcon\Security\Random class makes it really easy to generate lots of types of random data.

  1. <?php
  2. use Phalcon\Security\Random;
  3. $random = new Random();
  4. // ...
  5. $bytes = $random->bytes();
  6. // Generate a random hex string of length $len.
  7. $hex = $random->hex($len);
  8. // Generate a random base64 string of length $len.
  9. $base64 = $random->base64($len);
  10. // Generate a random URL-safe base64 string of length $len.
  11. $base64Safe = $random->base64Safe($len);
  12. // Generate a UUID (version 4). See https://en.wikipedia.org/wiki/Universally_unique_identifier
  13. $uuid = $random->uuid();
  14. // Generate a random integer between 0 and $n.
  15. $number = $random->number($n);

外部资源(External Resources)

  • Vökuró, 是一个使用的安全组件避免CSRF和密码散列的示例应用程序 [Github]