質問編集履歴
3
質問の修正
test
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
会員登録画面から直接メールアドレスに認証コードを送る場合セキュリティ対策として確認画面を設けるべきでしょうか?
|
test
CHANGED
@@ -1,63 +1,71 @@
|
|
1
1
|
### 実現したいこと
|
2
|
-
|
2
|
+
会員登録画面からメールアドレスに認証コードを送りたい。
|
3
3
|
|
4
4
|
### 発生している問題・分からないこと
|
5
|
-
|
5
|
+
以前お問い合わせページを作成した際に CSRF対策として入力画面からワンタイムトークンを作成して、確認画面でそのトークンが一致するかどうかをチェックするという仕組みを作成したのですが、会員登録画面(入力画面)からメールアドレスに送るタイミングでワンタイムトークンを作成してチェックするということは可能でしょうか?
|
6
6
|
|
7
7
|
|
8
8
|
|
9
9
|
### 該当のソースコード
|
10
10
|
|
11
|
+
```HTML
|
12
|
+
<div class="login-email">
|
13
|
+
<form method="post" class="register_form">
|
14
|
+
<div class="form_item">
|
15
|
+
|
16
|
+
<!-- <div class="login-inputWrapper"></div> -->
|
17
|
+
<!-- hiddenで生成したトークンを埋め込む -->
|
18
|
+
<!-- oninputプロパティは一定時間操作が無かったら処理を実行させる関数 -->
|
19
|
+
<input type="hidden" id="input-email" name="csrf_token" maxlength="15" oninput="value=value.replace(/[^\d]/g, '')" placeholder="メールアドレスを入力してください" value="<?= $csrf_token; ?>">
|
20
|
+
|
21
|
+
<div id="error-msg-email" class="error-msg" style="display: none;"></div>
|
22
|
+
|
23
|
+
<div class="login-email_vertical-line"></div>
|
24
|
+
<div class="login-email-send clickable disabled">
|
25
|
+
<font style="vertical-align: inherit;">
|
26
|
+
<font style="vertical-align: inherit;">認証コードを取得する</font>
|
27
|
+
</font>
|
28
|
+
</div>
|
29
|
+
</div>
|
30
|
+
|
31
|
+
<div class="form_separator-line"></div>
|
32
|
+
<div class="form_item">
|
33
|
+
<div>
|
34
|
+
<font style="vertical-align: inherit;">
|
35
|
+
<font style="vertical-align: inherit;">ハンドルネーム</font>
|
36
|
+
</font>
|
37
|
+
</div><input placeholder="ハンドルネームを入力してください" maxlength="6" oninput="value=value.replace(/[^\d]/g, '')">
|
38
|
+
</div>
|
39
|
+
|
40
|
+
<div class="form_separator-line"></div>
|
41
|
+
<div class="form_item">
|
42
|
+
<div>
|
43
|
+
<font style="vertical-align: inherit;">
|
44
|
+
<font style="vertical-align: inherit;">検証コード</font>
|
45
|
+
</font>
|
46
|
+
</div><input placeholder="確認コードを入力してください" maxlength="6" oninput="value=value.replace(/[^\d]/g, '')">
|
47
|
+
</div>
|
48
|
+
<input type="hidden" name="csrf_token" value="<?php echo $csrf_token; ?>" />
|
49
|
+
<!-- ↑追加 -->
|
50
|
+
<!-- </div> -->
|
51
|
+
</form>
|
52
|
+
</div>
|
53
|
+
```
|
54
|
+
|
11
55
|
```PHP
|
12
56
|
<?php
|
13
|
-
// 入力受け取り
|
14
|
-
$name = $_POST['name'];
|
15
|
-
$mail = $_POST['mail'];
|
16
|
-
|
17
|
-
// string は $mail という引数が「文字列型」であることを表しています。
|
18
|
-
// : bool は「この関数は 戻り値(returnする値)として、boolean型(trueかfalse)を返しますよ」という意味です。
|
19
|
-
// 「文字列 $mail を受け取って、結果を真偽値(true または false)で返す関数」という宣言になります
|
20
|
-
function checkmail(string $mail): bool
|
21
|
-
{
|
22
|
-
// 文字列 $mail を \`@\` を区切り文字として分割し、その結果を配列 $array に格納します。つまり、メールアドレスをユーザー名とドメインに分割します。
|
23
|
-
$array = explode('@', $mail);
|
24
|
-
// 配列 array の最後の要素の値を取り出して返します
|
25
|
-
$domain_part = array_pop($array);
|
26
|
-
// Filter 関数 の filter_var と ネットワーク関数 の checkdnsrr を利用してバリデーションを実装
|
27
|
-
// FILTER_VALIDATE_EMAIL は RFC 822 に準拠しているメールアドレスか否かを検証します。
|
28
|
-
// ネットワーク関数 の checkdnsrr を利用します。第二引数の DNS レコードの種類には、MX, A, AAAA を指定します。又、第二引数の既定値は MX です。
|
29
|
-
// これで、メール送信の可不可を確認することができます。
|
30
|
-
return filter_var($mail, FILTER_VALIDATE_EMAIL) !== false &&
|
31
|
-
(checkdnsrr($domain_part) || checkdnsrr($domain_part, 'A') || checkdnsrr($domain_part, 'AAAA'));
|
32
|
-
}
|
33
|
-
|
34
|
-
// 先頭から末尾まで、文字(漢字・ひらがな・英字)、数字、スペース、ハイフンだけで構成されているかチェックする
|
35
|
-
if (!preg_match('/^[\p{L}\p{N}\s\-]+$/u', $name)) {
|
36
|
-
die('不正な名前です');
|
37
|
-
}
|
38
|
-
|
39
|
-
// サニタイズ(タグ除去)
|
40
|
-
$name = strip_tags($name);
|
41
|
-
|
42
|
-
// メール内容
|
43
|
-
$subject = "DMM:会員登録認証メール";
|
44
|
-
$message = "お名前: {$name}\nメールアドレス: {$email}\nお問い合わせを受け付けました。";
|
45
|
-
|
46
|
-
// メールヘッダ(テキストメール指定)
|
47
|
-
$headers = "From: noreply@example.com\r\n";
|
48
|
-
$headers .= "Content-Type: text/plain; charset=UTF-8";
|
49
|
-
|
50
|
-
// メール送信
|
51
|
-
mail($email, $subject, $message, $headers);
|
52
|
-
|
53
|
-
/* ======================================================================================================== */
|
54
|
-
|
55
57
|
$_SESSION = array(); //セッション変数の初期化
|
56
58
|
session_start(); //セッションの開始
|
57
59
|
|
58
60
|
// 変数の宣言
|
59
61
|
// $error_message = '';
|
60
62
|
$mail = '';
|
63
|
+
|
64
|
+
// エラーが発生している時の処理
|
65
|
+
/* if (!empty($_SESSION['error_message'])) {
|
66
|
+
$error_message = $_SESSION['error_message'];
|
67
|
+
unset($_SESSION['error_message']);
|
68
|
+
} */
|
61
69
|
|
62
70
|
// ワンタイムトークン生成
|
63
71
|
$toke_byte = openssl_random_pseudo_bytes(16);
|
@@ -98,172 +106,6 @@
|
|
98
106
|
?>
|
99
107
|
```
|
100
108
|
|
101
|
-
```Javascript
|
102
|
-
<div class="bili-mini-login-right-wp">
|
103
|
-
<div data-v-35ff7abe="" class="login-tab-wp">
|
104
|
-
<div data-v-35ff7abe="" class="login-tab-item">
|
105
|
-
<font style="vertical-align: inherit;">
|
106
|
-
<font style="vertical-align: inherit;">パスワードログイン</font>
|
107
|
-
</font>
|
108
|
-
</div>
|
109
|
-
<div data-v-35ff7abe="" class="login-tab-line"></div>
|
110
|
-
<div data-v-35ff7abe="" class="login-tab-item active-tab">
|
111
|
-
<font style="vertical-align: inherit;">
|
112
|
-
<font style="vertical-align: inherit;">SMSログイン</font>
|
113
|
-
</font>
|
114
|
-
</div>
|
115
|
-
</div>
|
116
|
-
|
117
|
-
<style>
|
118
|
-
/* フォーカスが当たった時の青枠を表示しない */
|
119
|
-
*:focus {
|
120
|
-
outline: none;
|
121
|
-
}
|
122
|
-
|
123
|
-
/* エラーメッセージのスタイル */
|
124
|
-
div.error-msg p {
|
125
|
-
color: #e52d77;
|
126
|
-
margin: 0 0 0 8rem;
|
127
|
-
}
|
128
|
-
|
129
|
-
/* 入力欄 */
|
130
|
-
input[type="email"] {
|
131
|
-
line-height: 2em;
|
132
|
-
}
|
133
|
-
|
134
|
-
/* クリック時に枠の色を変更 */
|
135
|
-
○○○:hover {
|
136
|
-
border: 2px solid #000;
|
137
|
-
}
|
138
|
-
</style>
|
139
|
-
|
140
|
-
|
141
|
-
<div class="login-email">
|
142
|
-
<form method="post" class="register_form">
|
143
|
-
<div class="form_item">
|
144
|
-
|
145
|
-
<!-- <div class="login-inputWrapper"></div> -->
|
146
|
-
<!-- hiddenで生成したトークンを埋め込む -->
|
147
|
-
<!-- oninputプロパティは一定時間操作が無かったら処理を実行させる関数 -->
|
148
|
-
<input type="hidden" id="input-email" name="csrf_token" maxlength="15" oninput="value=value.replace(/[^\d]/g, '')" placeholder="メールアドレスを入力してください" value="<?= $csrf_token; ?>">
|
149
|
-
|
150
|
-
<div id="error-msg-email" class="error-msg" style="display: none;"></div>
|
151
|
-
|
152
|
-
<div class="login-email_vertical-line"></div>
|
153
|
-
<div class="login-email-send clickable disabled">
|
154
|
-
<font style="vertical-align: inherit;">
|
155
|
-
<font style="vertical-align: inherit;">認証コードを取得する</font>
|
156
|
-
</font>
|
157
|
-
</div>
|
158
|
-
</div>
|
159
|
-
|
160
|
-
<div class="form_separator-line"></div>
|
161
|
-
<div class="form_item">
|
162
|
-
<div>
|
163
|
-
<font style="vertical-align: inherit;">
|
164
|
-
<font style="vertical-align: inherit;">ハンドルネーム</font>
|
165
|
-
</font>
|
166
|
-
</div><input placeholder="ハンドルネームを入力してください" maxlength="6" oninput="value=value.replace(/[^\d]/g, '')">
|
167
|
-
</div>
|
168
|
-
|
169
|
-
<div class="form_separator-line"></div>
|
170
|
-
<div class="form_item">
|
171
|
-
<div>
|
172
|
-
<font style="vertical-align: inherit;">
|
173
|
-
<font style="vertical-align: inherit;">検証コード</font>
|
174
|
-
</font>
|
175
|
-
</div><input placeholder="確認コードを入力してください" maxlength="6" oninput="value=value.replace(/[^\d]/g, '')">
|
176
|
-
</div>
|
177
|
-
<input type="hidden" name="csrf_token" value="<?php echo $csrf_token; ?>" />
|
178
|
-
<!-- ↑追加 -->
|
179
|
-
<!-- </div> -->
|
180
|
-
</form>
|
181
|
-
|
182
|
-
<script>
|
183
|
-
// メールアドレスの入力チェック
|
184
|
-
var inputEmail = document.getElementById('input-email');
|
185
|
-
|
186
|
-
/**
|
187
|
-
* フォーカスが外れた場合のイベントハンドラ
|
188
|
-
*/
|
189
|
-
inputEmail.addEventListener('blur', function() {
|
190
|
-
// 入力されたメールアドレスを取得してトリム(データの不要な部分を削除し、必要な部分だけを残して値を設定し直す)して値を設定し直す
|
191
|
-
// 通常は値の設定前に文字列の先頭と末尾の空白を削除するためにトリムする必要があります。
|
192
|
-
inputEmail.value = inputEmail.value.trim();
|
193
|
-
|
194
|
-
// 入力チェック
|
195
|
-
// カスタムバリデーション名
|
196
|
-
validate_email();
|
197
|
-
});
|
198
|
-
|
199
|
-
/**
|
200
|
-
* メールアドレスの入力チェック
|
201
|
-
*/
|
202
|
-
function validate_email() {
|
203
|
-
|
204
|
-
var val = inputEmail.value;
|
205
|
-
|
206
|
-
// 必須チェック
|
207
|
-
if (val == "") {
|
208
|
-
// エラーメッセージの作成
|
209
|
-
var err_msg = document.createElement('p');
|
210
|
-
err_msg.textContent = 'メールアドレスが入力されていません。';
|
211
|
-
|
212
|
-
// エラーメッセージの表示領域
|
213
|
-
// var err_msg_div = document.querySelectorAll('#error-msg-email');
|
214
|
-
var err_msg_div = document.getElementById('error-msg-email');
|
215
|
-
|
216
|
-
// エラーメッセージの表示領域を表示する
|
217
|
-
err_msg_div.style.display = "block";
|
218
|
-
|
219
|
-
// エラーメッセージの表示領域にエラーメッセージを追加
|
220
|
-
err_msg_div.appendChild(err_msg);
|
221
|
-
|
222
|
-
// 入力欄にinput-errorクラスを追加(入力フォームの色を変更)
|
223
|
-
// input_email.setAttribute('class', 'input-error');
|
224
|
-
|
225
|
-
return;
|
226
|
-
}
|
227
|
-
// メールアドレス形式チェック
|
228
|
-
var regex = new RegExp(/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/);
|
229
|
-
if (!regex.test(val)) {
|
230
|
-
// エラーメッセージの作成
|
231
|
-
var err_msg = document.createElement('p');
|
232
|
-
err_msg.textContent = '無効なメールアドレスです。';
|
233
|
-
|
234
|
-
// エラーメッセージの表示領域
|
235
|
-
var err_msg_div = document.getElementById('error-msg-email');
|
236
|
-
|
237
|
-
// エラーメッセージの表示領域を表示する
|
238
|
-
err_msg_div.style.display = "block";
|
239
|
-
|
240
|
-
// エラーメッセージの表示領域にエラーメッセージを追加
|
241
|
-
err_msg_div.appendChild(err_msg);
|
242
|
-
|
243
|
-
// 入力欄にinput-errorクラスを追加(入力フォームの色を変更)
|
244
|
-
// input_email.setAttribute('class', 'input-error');
|
245
|
-
|
246
|
-
return;
|
247
|
-
}
|
248
|
-
}
|
249
|
-
|
250
|
-
/**
|
251
|
-
* フォーカスが当たった場合のイベントハンドラ
|
252
|
-
*/
|
253
|
-
input_email.addEventListener('focus', function() {
|
254
|
-
|
255
|
-
// input-errorクラスを削除
|
256
|
-
input_email.classList.remove('input-error');
|
257
|
-
|
258
|
-
// エラーメッセージの表示領域を非表示にする
|
259
|
-
document.getElementById('error-msg-email').style.display = "none";
|
260
|
-
|
261
|
-
// エラーメッセージを削除
|
262
|
-
document.getElementById('error-msg-email').children[0].remove();
|
263
|
-
});
|
264
|
-
</script>
|
265
|
-
```
|
266
|
-
|
267
109
|
### 試したこと・調べたこと
|
268
110
|
- [x] teratailやGoogle等で検索した
|
269
111
|
- [x] ソースコードを自分なりに変更した
|
@@ -271,10 +113,10 @@
|
|
271
113
|
- [x] その他
|
272
114
|
|
273
115
|
##### 上記の詳細・結果
|
274
|
-
サーバーサイドでセキュリティ対策となるコードを書いてい
|
116
|
+
今後サーバーサイドでセキュリティ対策となるコードを書いていく際に確認画面を設けない場合にメールアドレスに直接送信する方法では攻撃を防ぎきれないのではないかと心配しております。
|
275
117
|
|
276
118
|
### 補足
|
277
119
|
※ 参考サイト
|
278
120
|
https://html-coding.co.jp/knowhow/security/csrf/
|
279
121
|
|
280
|
-
https://
|
122
|
+
https://note.com/kohki/n/na9b4bddfa717
|
2
誤字
test
CHANGED
File without changes
|
test
CHANGED
@@ -276,3 +276,5 @@
|
|
276
276
|
### 補足
|
277
277
|
※ 参考サイト
|
278
278
|
https://html-coding.co.jp/knowhow/security/csrf/
|
279
|
+
|
280
|
+
https://www.spiral-platform.co.jp/article/form/16286/
|
1
誤字
test
CHANGED
File without changes
|
test
CHANGED
@@ -131,13 +131,6 @@
|
|
131
131
|
line-height: 2em;
|
132
132
|
}
|
133
133
|
|
134
|
-
/* 入力エラーがあった時のスタイル(エラーがあった時は枠の色は分かりずらいので変更せずエラー文のみ表示させる)
|
135
|
-
.input-error {
|
136
|
-
border: 1px solid #e52d77;
|
137
|
-
border-radius: 3px;
|
138
|
-
background-color: #FCC;
|
139
|
-
} */
|
140
|
-
|
141
134
|
/* クリック時に枠の色を変更 */
|
142
135
|
○○○:hover {
|
143
136
|
border: 2px solid #000;
|