Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
80.00% |
12 / 15 |
|
33.33% |
1 / 3 |
CRAP | |
0.00% |
0 / 1 |
WebSecurity | |
80.00% |
12 / 15 |
|
33.33% |
1 / 3 |
9.65 | |
0.00% |
0 / 1 |
getCsrfKind | |
83.33% |
5 / 6 |
|
0.00% |
0 / 1 |
5.12 | |||
getCsrfTokenHash | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
generateCsrfToken | |
75.00% |
6 / 8 |
|
0.00% |
0 / 1 |
3.14 |
1 | <?php |
2 | |
3 | declare(strict_types=1); |
4 | |
5 | namespace PeServer\Core\Web; |
6 | |
7 | use PeServer\Core\Binary; |
8 | use PeServer\Core\Cryptography; |
9 | use PeServer\Core\MiddlewareArgument; |
10 | use PeServer\Core\Text; |
11 | use PeServer\Core\Throws\SessionException; |
12 | |
13 | class WebSecurity |
14 | { |
15 | #region define |
16 | |
17 | public const CSRF_KIND_SESSION_KEY = 1; |
18 | public const CSRF_KIND_REQUEST_ID = 2; |
19 | public const CSRF_KIND_REQUEST_NAME = 3; |
20 | public const CSRF_KIND_HEADER_NAME = 4; |
21 | |
22 | private const CSRF_SESSION_KEY = 'core__csrf'; |
23 | private const CSRF_REQUEST_ID = 'core__csrf_id'; |
24 | private const CSRF_REQUEST_NAME = 'core__csrf_name'; |
25 | private const CSRF_HEADER_NAME = 'X-CSRF-TOKEN'; |
26 | |
27 | private const CSRF_HASH_ALGORITHM = 'sha256'; |
28 | |
29 | #endregion |
30 | |
31 | #region function |
32 | |
33 | /** |
34 | * CSRFに関する項目名等々を取得。 |
35 | * |
36 | * HTTP/HTML上のキーに関するのものが対象となる。 |
37 | * |
38 | * @param int $kind |
39 | * @phpstan-param self::CSRF_KIND_* $kind |
40 | * @return non-empty-string |
41 | */ |
42 | public function getCsrfKind(int $kind): string |
43 | { |
44 | return match ($kind) { |
45 | self::CSRF_KIND_SESSION_KEY => self::CSRF_SESSION_KEY, |
46 | self::CSRF_KIND_REQUEST_ID => self::CSRF_REQUEST_ID, |
47 | self::CSRF_KIND_REQUEST_NAME => self::CSRF_REQUEST_NAME, |
48 | self::CSRF_KIND_HEADER_NAME => self::CSRF_HEADER_NAME, |
49 | }; |
50 | } |
51 | |
52 | /** |
53 | * CSRFトークンのハッシュアルゴリズム。 |
54 | * @return non-empty-string |
55 | */ |
56 | protected function getCsrfTokenHash(): string |
57 | { |
58 | return self::CSRF_HASH_ALGORITHM; |
59 | } |
60 | |
61 | /** |
62 | * CSRFトークンを取得。 |
63 | * |
64 | * @return non-empty-string |
65 | * @throws SessionException セッションID取得失敗。 |
66 | */ |
67 | public function generateCsrfToken(): string |
68 | { |
69 | $sessionId = session_id(); |
70 | if ($sessionId === false) { |
71 | throw new SessionException('セッションID取得失敗'); |
72 | } |
73 | |
74 | $algorithm = $this->getCsrfTokenHash(); |
75 | $hash = Cryptography::generateHashString($algorithm, new Binary($sessionId)); |
76 | if (Text::isNullOrEmpty($hash)) { |
77 | throw new SessionException('CSRFトークン生成失敗'); |
78 | } |
79 | |
80 | return $hash; |
81 | } |
82 | |
83 | #endregion |
84 | } |