Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.00% covered (warning)
80.00%
12 / 15
33.33% covered (danger)
33.33%
1 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
WebSecurity
80.00% covered (warning)
80.00%
12 / 15
33.33% covered (danger)
33.33%
1 / 3
9.65
0.00% covered (danger)
0.00%
0 / 1
 getCsrfKind
83.33% covered (warning)
83.33%
5 / 6
0.00% covered (danger)
0.00%
0 / 1
5.12
 getCsrfTokenHash
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 generateCsrfToken
75.00% covered (warning)
75.00%
6 / 8
0.00% covered (danger)
0.00%
0 / 1
3.14
1<?php
2
3declare(strict_types=1);
4
5namespace PeServer\Core\Web;
6
7use PeServer\Core\Binary;
8use PeServer\Core\Cryptography;
9use PeServer\Core\MiddlewareArgument;
10use PeServer\Core\Text;
11use PeServer\Core\Throws\SessionException;
12
13class 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}