現在、Javaプロジェクトでパスワードを忘れた場合の機能を実装しています。私の方法論は、
パスワードのリセットページのemail address
フィールドの編集(読み取り専用フィールド)を制限していますが、ブラウザのアドレスバーのURLを変更して、メールアドレスフィールドを変更できます。
すべてのユーザーがパスワードのリセットページでメールアドレスを変更できないように制限するにはどうすればよいですか?
トークンを使用してメールを送信する前に、DBに保存する必要があります。
email
、token
、expirationdate
token
を使用すると、サーバーはidentify the user
、有効期限のおかげでリクエストの有効期限が切れていないか確認し、正しいメールをボックスに入れて、パスワードの更新を要求します。ユーザーが新しいパスワードを入力すると、トークン(hidden field
の形式)+サーバーへのパスワード。サーバーはメールのテキストボックスを気にしません。なぜならwith the token, user is identified strongly
expirationdate
(再度)で有効かどうかを確認し、password match
そして大丈夫なら、新しいパスワードを保存してください!サーバーは、リクエストによりパスワードが変更されたことをユーザーに通知するために、メッセージを再送信できます。これは本当に安全です。 expirationdate
に短い時間を使用してセキュリティを改善し(たとえば5分が正しい)、強力なトークンを使用してください(GUIDとして、コメントを参照)
パスワードを忘れた場合の機能を自分で実装する必要がある場合は、@ clementの回答に同意します。この実装の合理的で安全な方法のように思えます。
ただし、代わりに、自分で実装する必要がない場合は、 Stormpath のような、これを行うサービスを使用することをお勧めします。
Stormpathを使用することにした場合、機能をトリガーするコードは、Java(StormpathのJava SDK)で次のようになります。
Account account = application.sendPasswordResetEmail("[email protected]");
ユーザーには次のようなリンクが記載されたメールが届きます。
http://yoursite.com/path/to/reset/page?sptoken=$TOKEN
そして、ユーザーがリンクをクリックすると、次のようにパスワードを確認してリセットします。
Account account = application.resetPassword("$TOKEN", "newPassword");
この仕組みの詳細については、Stormpathの パスワードリセットドキュメント をご覧ください。
このアプローチを使用すると、実装しないオプションがある場合、機能を実装および維持する必要はありません。
注:Stormpathは Okta に参加しました。
メールアドレスをユーザーによる変更に制限することはできません。
非表示にしたり、テキストボックスを読み取り専用にした場合でも、ブラウザでソースコードを編集することで、メールアドレスを簡単に変更できます。
uniq random string or token
リセットリンクを使用し、パスワードのリセットリンクをクリックした後、またはユーザーがデータベース内の電子メールアドレスとトークン文字列でリクエストの電子メールアドレスとトークン文字列を確認してリセットパスワードのリクエストを送信した後、電子メールアドレスとトークンの組み合わせを確認します。
データベースに電子メールアドレスが存在する場合、それは電子メールアドレスが有効であることを意味し、そうでない場合は、ユーザーレコードに電子メールアドレスが存在しないというメッセージを伝えます。
注:
フレームワークまたは単にサーブレットを使用している場合は、リンクを提供するよりも良いので、パスワードのリセットフォームを表示する前にメールとトークン文字列を検証できます。トークン文字列または電子メールアドレスが無効な場合、ユーザーはパスワードのリセット要求の送信を制限し、要求の送信後に検証できます。パスワードのリセット要求を送信した後の検証よりも安全です。
この質問は、この回答の3年前に投稿されました...しかし、私はそれが他の人に役立つかもしれないと思います。
要するに、私はあなたの流れに完全に同意します。非常に安全に見えますが、あなたの唯一のオープンエンドも理にかなっています-誰もユーザー名を変更しないことを確認し、それによって彼に新しいパスワードを設定できます。
(受け入れられた答えが示唆するように)一時的に物事を保存するという考え方はDBほど好きではありません。
私が考えていたアイデアは、ユーザーに送信されるリンクのデータに署名することでした。次に、ユーザーがリンクをクリックしてサーバーが呼び出しを受信すると、サーバーも暗号化された部分を取得し、データが変更されていないことを検証できます。
ちなみに(ここで「プロモーション」が来る):私はこれらのユースケースのためにJavaプロジェクト(「アカウントを作成」、「パスワードを変更」など)を実装しました。オープンソースのGitHubは、Spring Securityの上にJavaで実装された、あなたの質問に完璧に答えます。
すべての説明があります(何かが足りない場合はお知らせください...)
ご覧ください: https://github.com/OhadR/oAuth2-sample/tree/master/authentication-flows
デモはこちら を参照してください。
Auth-flowを使用するクライアントWebアプリもあります。README=すべての説明付き: https://github.com/OhadR/Authentication-Flows =
2つの一般的なソリューションがあります。
1. Creating a new password on the server and inform user from it.
2. Sending a unique URL to reset password.
最初のソリューションには多くの問題があり、使用するのは適切ではありません。これらはいくつかの理由です:
1. The new password which is created by server should be sent through an insecure channel (such as email, sms, ...) and resides in your inbox.
2. If somebody know the email address or phone number of a user who has an account at a website then then it is possible to reset user password.
したがって、2番目のソリューションを使用することをお勧めします。ただし、次の問題を考慮する必要があります。
- The reset url should be random, not something guessable and unique to this specific instance of the reset process.
- It should not consist of any external information to the user For example, a reset URL should not simply be a path such as “.../?username=Michael”.
- We need to ensure that the URL is loaded over HTTPS. No, posting to HTTPS is not enough, that URL with the token must implement transport layer
security so that the new password form cannot be MITM’d and the password the user creates is sent back over a secure connection.
- The other thing we want to do with a reset URL is setting token's expiration time so that the reset process must be completed within a certain duration.
- The reset process must run once completely. So, Reset URL can not be appilicable if the reset process is done completely once.
一般的な解決策は、URLパラメータとして送信できる一意のトークンを作成するURLを生成することです。これには、「Reset /?id = 2ae755640s15cd3si8c8i6s2cib9e14a1ae552b」などのURLが含まれます。
パスワードを忘れた場合の完全なコードを探している場合は、ここでコードを共有します。必要な場所にリンクを配置します。
<button> <a href="forgotpassword.jsp" style="text-decoration:none;">Forgot
Password</a></button>
以下は私のforgotpassword.jsp
ページです。
<form id="register-form" role="form" class="form" method="post"
action="mymail_fp.jsp">
<h3>Enter Your Email Below</h3>
<input id="email" name="email" placeholder="Email address" class="form-
control" type="email" required autofocus>
<input name="recover-submit" class="btn btn-lg btn-primary btn-block"
value="Get Password" type="submit">
</form>
電子メールが送信されると、mymail_fp.jsp
ページにリダイレクトされ、ユーザーに電子メールが送信されます。以下はmymail.jsp
ページです。
<%
mdjavahash md = new mdjavahash();
String smail =request.getParameter("email");
int profile_id = 0;
if(smail!=null)
{
try{
// Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
// Open a connection
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/infoshare", "root",
"");
Statement stmt = conn.createStatement();
String sql1;
sql1="SELECT email FROM profile WHERE email = '"+smail+"'";
ResultSet rs1=stmt.executeQuery(sql1);
if(rs1.first())
{
String sql;
sql = "SELECT Profile_id FROM profile where email='"+smail+"'";
ResultSet rs2 = stmt.executeQuery(sql);
// Extract data from result set
while(rs2.next()){
//Retrieve by column name
profile_id = rs2.getInt("Profile_id");
}
Java.sql.Timestamp intime = new Java.sql.Timestamp(new
Java.util.Date().getTime());
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(intime.getTime());
cal.add(Calendar.MINUTE, 20);
Java.sql.Timestamp exptime = new Timestamp(cal.getTime().getTime());
int Rand_num = (int) (Math.random() * 1000000);
String Rand = Integer.toString(Rand_num);
String finale =(Rand+""+intime); //
String hash = md.getHashPass(finale); //hash code
String save_hash = "insert into reset_password (Profile_id, hash_code,
exptime, datetime) values("+profile_id+", '"+hash+"', '"+exptime+"',
'"+intime+"')";
int saved = stmt.executeUpdate(save_hash);
if(saved>0)
{
String link = "http://localhost:8080/Infoshare/reset_password.jsp";
//bhagawat till here, you have fetch email and verified with the email
from
datbase and retrived password from the db.
//-----------------------------------------------
String Host="", user="", pass="";
Host = "smtp.gmail.com"; user = "[email protected]";
//"email@removed" // email id to send the emails
pass = "xxxx"; //Your gmail password
String SSL_FACTORY = "javax.net.ssl.SSLSocketFactory";
String to = smail;
String from = "[email protected]";
String subject = "Password Reset";
String messageText = " Click <a href="+link+"?key="+hash+">Here</a> To
Reset
your Password. You must reset your password within 20
minutes.";//messageString;
String fileAttachment = "";
boolean WasEmailSent ;
boolean sessionDebug = true;
Properties props = System.getProperties();
props.put("mail.Host", Host);
props.put("mail.transport.protocol.", "smtp");
props.put("mail.smtp.auth", "true");
props.put("mail.smtp.", "true");
props.put("mail.smtp.port", "465");
props.put("mail.smtp.socketFactory.fallback", "false");
props.put("mail.smtp.socketFactory.class", SSL_FACTORY);
Session mailSession = Session.getDefaultInstance(props, null);
mailSession.setDebug(sessionDebug);
Message msg = new MimeMessage(mailSession);
msg.setFrom(new InternetAddress(from));
InternetAddress[] address = {new InternetAddress(to)};
msg.setRecipients(Message.RecipientType.TO, address);
msg.setSubject(subject);
msg.setContent(messageText, "text/html");
Transport transport = mailSession.getTransport("smtp");
transport.connect(Host, user, pass);
%>
<div class="alert success" style="padding: 30px; background-color: grey;
color: white; opacity: 1; transition: opacity 0.6s; width:50%; margin: 10%
5%
15% 20%;">
<a href="forgotpassword.jsp"> <span class="closebtn" style="color: white;
font-weight: bold; float: right; font-size: 40px; line-height: 35px; cursor:
pointer; transition: 0.3s;">×</span> </a>
<h1 style="font-size:30px;"> <strong>Check Your Email. Link To
Reset Your Password Is Sent To : <%out.println(" "+smail); %></strong>
</h1>
<center><a href="forgotpassword.jsp"><h2><input type="button" value="OK">
</h2></a></center>
</div>
<%
try {
transport.sendMessage(msg, msg.getAllRecipients());
WasEmailSent = true; // assume it was sent
}
catch (Exception err) {
WasEmailSent = false; // assume it's a fail
}
transport.close();
//-----------------------------------------------
}
}
else{
%>
<div class="alert success" style="padding: 30px; background-color: grey;
color: white; opacity: 1; transition: opacity 0.6s; width:50%; margin: 10%
5% 15% 20%;">
<a href="forgotpassword.jsp"> <span class="closebtn" style="color:
white; font-weight: bold; float: right; font-size: 40px; line-height: 35px;
cursor: pointer; transition: 0.3s;">×</span> </a>
<h1 style="font-size:30px;"> <strong>There Is No Email As
Such <%out.println(" "+smail); %></strong>Try Again </h1>
<center><a href="forgotpassword.jsp"><h2><input type="button"
value="OK"></h2></a></center>
</div>
<%
}
stmt.close();
rs1.close();
conn.close();
}catch(SQLException se){
//Handle errors for JDBC
se.printStackTrace();
}catch(Exception e){
//Handle errors for Class.forName
e.printStackTrace();
}
}
else{
%>
<div class="alert success" style="padding: 30px; background-color: grey;
color: white; opacity: 1; transition: opacity 0.6s; width:50%; margin: 10%
5% 15% 20%;">
<a href="forgotpassword.jsp"> <span class="closebtn" style="color: white;
font-weight: bold; float: right; font-size: 40px; line-height: 35px;
cursor:
pointer; transition: 0.3s;">×</span> </a>
<h1 style="font-size:30px;"> <strong>Please Enter The Valid
Email Address</strong> </h1>
<center><a href="forgotpassword.jsp"><h2><input type="button" value="OK">
</h2></a></center>
</div>
<%
}
%>
ここで私がやったことは、ユーザーにメールを送信する前に、送信時間を節約し、有効期限を0から1000000までの乱数を生成し、送信時間と連結して暗号化し、リンク内のクエリ文字列として送信しますEメール。そのため、メールが送信され、パスワードへのリンクがハッシュキーとともに送信されます。ユーザーがリンクをクリックすると、reset_password.jspに送信され、次はreset_password.jsp
ページになります。
<%
String hash = (request.getParameter("key"));
Java.sql.Timestamp curtime = new Java.sql.Timestamp(new
Java.util.Date().getTime());
int profile_id = 0;
Java.sql.Timestamp exptime;
try{
// Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
// Open a connection
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/infoshare", "root",
"");
Statement stmt = conn.createStatement();
String sql = "select profile_id, exptime from reset_password where
hash_code ='"+hash+"'";
ResultSet rs = stmt.executeQuery(sql);
if(rs.first()){
profile_id = rs.getInt("Profile_id");
exptime = rs.getTimestamp("exptime");
//out.println(exptime+"/"+curtime);
if((curtime).before(exptime)){
%>
<div class="container">
<form class="form-signin" action="update_reset.jsp" method="Post">
<br/><br/>
<h4 class="form-signin-heading">Reset Your Password Here</h4>
<br>
<text style="font-size:13px;"><span class="req"
style="color:red">* </span>Enter New Password</text>
<input type="password" id="inputPassword" name="newpassword"
class="form-control" placeholder="New Password" required autofocus>
<br>
<text style="font-size:13px;"><span class="req"
style="color:red">* </span>Enter New Password Again</text>
<input type="password" id="inputPassword" name="confirmpassword"
class="form-control" placeholder="New Password Again" required>
<input type="hidden" name="profile_id" value=<%=profile_id %>>
<br>
<button class="btn btn-lg btn-primary btn-block"
type="submit">Reset Password</button>
</form>
</div> <!-- /container -->
<% }
else{
%>
<div class="alert success" style="padding: 30px; background-color:
grey; color: white; opacity: 1; transition: opacity 0.6s; width:50%;
margin: 10% 5% 15% 20%;">
<a href="forgotpassword.jsp"> <span class="closebtn"
style="color: white; font-weight: bold; float: right; font-size: 40px;
line-height: 35px; cursor: pointer; transition: 0.3s;">×</span>
</a>
<h1 style="font-size:30px;"> The Time To Reset
Password Has Expired.<br> Try Again </h1>
<center><a href="forgotpassword.jsp"><h2><input type="button"
value="OK"></h2></a></center>
</div>
<%
}
}
else{
%>
<div class="alert success" style="padding: 30px; background-color: grey;
color: white; opacity: 1; transition: opacity 0.6s; width:50%; margin:
10% 5% 15% 20%;">
<a href="forgotpassword.jsp"> <span class="closebtn" style="color:
white; font-weight: bold; float: right; font-size: 40px; line-height:
35px; cursor: pointer; transition: 0.3s;">×</span> </a>
<h1 style="font-size:30px;"> The Hash Key DO Not Match.
<br/> Try Again!! </h1>
<center><a href="forgotpassword.jsp"><h2><input type="button"
value="OK"></h2></a></center>
</div>
<%
}
// Clean-up environment
rs.close();
stmt.close();
conn.close();
}catch(SQLException se){
//Handle errors for JDBC
se.printStackTrace();
}catch(Exception e){
e.printStackTrace();
}
%>
このページでは、ハッシュキーを取得し、データベースハッシュキーと比較します。それが正しい場合は、有効期限を取得して現在の時間と比較します。パスワードをリセットする時間が経過していない場合、パスワードをリセットするフォームを表示します。そうでない場合、エラーメッセージがスローされます。時間が経過していない場合、フォームを表示し、フォームが送信されると、update_reset.jsp
にリダイレクトされ、次にupdate_reset.jsp
ページが表示されます。
<%
mdjavahash md = new mdjavahash();
String profile_id= request.getParameter("profile_id");
String np= request.getParameter("newpassword");
String cp = request.getParameter("confirmpassword");
//out.println(np +"/"+ cp);
if( np.equals(" ") || cp.equals(" ")){%>
<div class="alert success" style="padding: 30px; background-color: grey;
color: white; opacity: 1; transition: opacity 0.6s; width:50%; margin: 10%
5% 15% 20%;">
<a href="reset_password?profile_id=<%=profile_id%>"> <span
class="closebtn" style="color: white; font-weight: bold; float: right;
font-size: 40px; line-height: 35px; cursor: pointer; transition:
0.3s;">×</span> </a>
<h1 style="font-size:30px;"> Please Fill Both The Fields
</h1>
<center><a href="reset_password?profile_id=<%=profile_id%>""><h2><input
type="button" value="OK"></h2></a></center>
</div>
<% }
else if(!np.equals(cp)){
%>
<div class="alert success" style="padding: 30px; background-color: grey;
color: white; opacity: 1; transition: opacity 0.6s; width:50%; margin: 10%
5% 15% 20%;">
<a href="reset_password?profile_id=<%=profile_id%>"> <span
class="closebtn" style="color: white; font-weight: bold; float: right;
font-size: 40px; line-height: 35px; cursor: pointer; transition:
0.3s;">×</span> </a>
<h1 style="font-size:30px;"> The Two Passwords Do Not
Match. Try Again </h1>
<center><a href="reset_password?profile_id=<%=profile_id%>"><h2>
<input type="button" value="OK"></h2></a></center>
</div>
<%
}
else{
try{
// Register JDBC driver
Class.forName("com.mysql.jdbc.Driver");
// Open a connection
Connection conn =
DriverManager.getConnection("jdbc:mysql://localhost:3306/infoshare",
"root", "");
// Execute SQL query
Statement stmt = conn.createStatement();
stmt.executeUpdate("update profile set
password='"+md.getHashPass(np)+"' where Profile_id="+profile_id+"");
//response.sendRedirect("mainpage.jsp");
%>
<div class="alert success" style="padding: 30px; background-color:
grey; color: white; opacity: 1; transition: opacity 0.6s; width:65%;
margin: 10% 5% 15% 20%;">
<a href="login.jsp"> <span class="closebtn" style="color: white;
font-weight: bold; float: right; font-size: 40px; line-height: 35px;
cursor: pointer; transition: 0.3s;">×</span> </a>
<h1 style="font-size:30px;"> The Password Is
Successfully Reset.<br> Try Login With New
Password</h1>
<br><br><center><a href="login.jsp"><p style="font-size:20px">
<input type="button" style="width:40px; height:35px;"
value="OK"></p></a>
</center>
</div>
<%
stmt.close();
conn.close();
}catch(SQLException se){
//Handle errors for JDBC
se.printStackTrace();
}catch(Exception e){
//Handle errors for Class.forName
e.printStackTrace();
}
}
%>
このページでは、最初にフィールドを検証してから、新しいパスワードでデータベースを更新します。それは長いですが、動作しますが。私はここでMD5暗号化技術を使用しましたが、どうすればいいですか?リンクをたどってください JavaScriptでJSPのログインパスワードを保護するためにMD5ハッシュを使用する方法?