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