PageRenderTime 48ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 0ms

/BEAR/Form/Token.php

https://github.com/koriym/BEAR.Saturday
PHP | 141 lines | 67 code | 14 blank | 60 comment | 7 complexity | 6797ede63991a0808c1af28e16517dff MD5 | raw file
  1. <?php
  2. /**
  3. * This file is part of the BEAR.Saturday package.
  4. *
  5. * @license http://opensource.org/licenses/bsd-license.php BSD
  6. */
  7. class BEAR_Form_Token extends BEAR_Base implements BEAR_Form_Token_Interface
  8. {
  9. /**
  10. * セッショントークンキー名
  11. *
  12. * @var string
  13. */
  14. const SESSION_TOKEN = 'stoken';
  15. /**
  16. * POE(Post Once Exactly)用トークンキー配列セッションキー名
  17. *
  18. * @var string
  19. */
  20. const SESSION_POE = 'poe_key';
  21. /**
  22. * CSRFキーの長さ
  23. *
  24. * @var int
  25. */
  26. const SESSION_CSRF_LEN = 20;
  27. /**
  28. * POEキーの長さ
  29. *
  30. * @var int
  31. */
  32. const SESSION_POE_LEN = 20;
  33. /**
  34. * @var BEAR_Session
  35. */
  36. protected $_tokenStrage;
  37. /**
  38. * Submit token
  39. *
  40. * @var string
  41. */
  42. protected $_submitToken;
  43. /**
  44. * @see BEAR_Base::onInject()
  45. */
  46. public function onInject()
  47. {
  48. $this->_tokenStrage = BEAR::dependency('BEAR_Session');
  49. if (isset($_POST['_token'])) {
  50. $token = $_POST['_token'];
  51. } elseif (isset($_GET['_token'])) {
  52. $token = $_GET['_token'];
  53. } else {
  54. $token = '';
  55. }
  56. $this->_submitToken = $token;
  57. }
  58. /**
  59. * トークン作成
  60. *
  61. * @return BEAR_Ro
  62. */
  63. public function newSessionToken()
  64. {
  65. $csrfToken = $this->_getRndToken(session_id(), self::SESSION_CSRF_LEN);
  66. $poeToken = $this->_getRndToken(uniqid(mt_rand(), true), self::SESSION_POE_LEN);
  67. $token = $csrfToken . $poeToken;
  68. $this->_tokenStrage->set(self::SESSION_TOKEN, $token);
  69. }
  70. /**
  71. * @see BEAR_Form_Token_Interface::getToken()
  72. */
  73. public function getToken()
  74. {
  75. $token = $this->_tokenStrage->get(self::SESSION_TOKEN);
  76. if ($token) {
  77. return $token;
  78. }
  79. // セッション不使用
  80. return sha1(session_id());
  81. }
  82. /**
  83. * @see BEAR_Form_Token_Interface::isTokenCsrfValid()
  84. */
  85. public function isTokenCsrfValid()
  86. {
  87. $sessToken = $this->_tokenStrage->get(self::SESSION_TOKEN);
  88. $sessToken = substr($sessToken, 0, self::SESSION_POE_LEN);
  89. $submitToken = substr($this->_submitToken, 0, self::SESSION_CSRF_LEN);
  90. return is_string($sessToken) && ($sessToken === $submitToken);
  91. }
  92. /**
  93. * @see BEAR_Form_Token_Interface::isTokenPoeValid()
  94. */
  95. public function isTokenPoeValid()
  96. {
  97. $poes = $this->_tokenStrage->get(self::SESSION_POE);
  98. $poes = is_array($poes) ? $poes : [];
  99. $isDoubleSubmit = in_array($this->_submitToken, $poes, true);
  100. if ($isDoubleSubmit) {
  101. return false;
  102. }
  103. // insert key
  104. $poes[] = $this->_submitToken;
  105. if (count($poes) > 3) {
  106. $poes = array_slice($poes, 1, 3);
  107. }
  108. $this->_tokenStrage->set(self::SESSION_POE, $poes);
  109. return true;
  110. }
  111. /**
  112. * 任意の長さの乱数文字列の取得
  113. *
  114. * @param string $salt
  115. * @param int $length
  116. *
  117. * @return string
  118. */
  119. protected function _getRndToken($salt, $length = null)
  120. {
  121. $sha = sha1($salt);
  122. if ($length === null) {
  123. return $sha;
  124. }
  125. return substr($sha, 0, $length);
  126. }
  127. }