データベースに保存されているパスワードを復号化します:
次のことがわかります。 MD5 アルゴリズムはハッシュ関数であり、ハッシュ アルゴリズムを使用しているため、計算プロセス中に元の情報の一部が失われるため、不可逆であることは誰もが知っているため、パスワードの復号化に成功したことに驚きました。では、なぜ私のパスワードが Web サイトで復号化されるのでしょうか?
いくつかの検索の結果、オンライン復号ツールの復号原理は非常に単純であることがわかりました。その原理は、ユーザーがよく使用する単純なパスワードを収集してパスワード辞書を作成し、その辞書内のパスワードを暗号化することです。いわゆる「復号化」の際、実際のユーザー パスワード暗号化の暗号文が保存されているパスワードと比較され、その暗号文が辞書に存在する場合は「復号化」できます。したがって、単純に MD5 を使用してユーザー パスワードを暗号化することは安全ではありません。パスワードを設定するとき、通常は複雑さの検出が行われます。たとえば、セキュリティ上の理由から、パスワードには英語の数字などが含まれている必要があります。
復号化の原理を理解した後、より複雑なパスワードを試して「復号化」できるかどうかを確認します。まず、パスワード「qweasd666」を暗号化します:
暗号化後、復号化のために 32 ビットの小文字の暗号文を選択します。
復号化に失敗した場合、原則として照合とクラッキングのために一般的に使用される暗号文を収集することを示します。 「qweasd666」パスワードは解読できないため、安全であり、皆さんもこのパスワード (doge) を使用できます。
本題に戻りますが、私が慎重に設定したパスワードをこの Web サイトで解読されてしまい、非常に不安になり、面目を失ったように感じました。ログインのセキュリティ レベルを向上させなければなりません。
上記の復号化操作に加えて、もう 1 つの大きな問題は、フロントエンドがデータを送信するときに http が平文送信を使用することです。送信データ パケットが傍受された場合、たとえバックエンドがどのようにしても暗号化アルゴリズムが複雑な場合、パスワードは他人に知られてしまいます。
問題が見つかったら、適切な薬を処方できます。まず、次の問題を解決する必要があると思います。 http 平文送信、これが一番リスクが高いので、パスワードは普通のパケットキャプチャで捕捉できますが、これって怖くないですか?平文での送信にはセキュリティの問題があるため、暗号化によって送信のセキュリティを確保できます。
現在も MD5 暗号化スキームを使用していますが、パスワードを暗号化する前に固定のソルト値を追加しています。塩?塩を加えているのでしょうか?実際はほとんど同じで、「調味料」を加えていると言ったほうが良いでしょう。基本的な考え方は次のとおりです: ユーザーが初めてパスワードを入力するとき (通常は登録時)、プログラムはパスワードに「ソース」を振りかけます。開発プレッシャーを軽減するために、この味付けはすべてのユーザーに対して同じです。もう一度ハッシュします。これにより、送信中の平文パスワードの漏洩を防ぎます。
上で述べたのは平文パスワードの漏洩を防ぐためですが、これは暗号文が漏洩しないという意味ではないことに注意してください。 http 経由で送信される 暗号化されたパスワード、またはデータベースの漏洩により、暗号化されたパスワードがハッカーによって盗まれます。ハッカーはフロントエンドの js ファイルを解析してフロントエンドの固定ソルト値を取得します。その後、ハッカーは次の操作を実行できる可能性があります。レインボー テーブルを介して逆クエリを実行して、元のパスワードを取得します。この時、二次暗号化の重要性が出てきますが、二次暗号化の原理は、フロントエンドから渡された暗号化されたパスワードとランダムなSalt値を組み合わせて暗号化することです(今回はランダムであることに注意してください)。 will ユーザーがログインするとランダムに生成され、データベースに保存されます。
この時点で、あなたは最初に私が抱いたのと同じ疑問を抱いているかもしれません。つまり、ランダムなソルト値をデータベースに保存したのですが、データベースが漏洩した場合、ランダムなソルト値はどうなるのでしょうか?ハッカーが暗号化されたデータを復号し、ソルト値を削除することでパスワードを取得することは可能ではないでしょうか?はい、ハッカーがそのような方法でパスワードを取得することは可能ですが、それは彼が復号化できる場合に限られます。知っておく必要があるのは、MD5 は直接クラックすることはできず、完全な方法でのみ復号化できるということです。たとえハッカーがデータベース内の暗号化されたパスワードを取得しても、バックエンドの暗号化プロセスを知らなかったとしても、それを解析することはできません。 「2 次暗号化では、この時点の暗号文は解析が困難です。暗号化されたデータの複雑さが増すにつれて、クラッキングのコストは指数関数的に増加します。このような莫大なコストを前に、喜んでハッカーはいないと思います」それを試してみてください。もちろん、ソルトは最初や最後に入れる必要はなく、途中に入れたり、別々に入れたり、逆に入れたりすることもでき、プログラム設計時に柔軟に調整できるため、難易度が飛躍的に高まります。ひび割れ。
2.3: 具体的な実装
2.3.1: ユーザー登録
フロントエンドは、ユーザーが入力したパスワードに対して md5 暗号化を実行します (固定ソルト) )
暗号化されたパスワードをバックエンドに渡します
バックエンドはランダムにソルトを生成します
[ソルトの生成] を使用してフロントエンドから渡されたパスワードを暗号化し、暗号化されたパスワードとソルトを db
に保存します。2.3.2: ユーザー ログイン
フロントエンドは、ユーザーが入力したパスワードに対して md5 暗号化を実行します (固定ソルト)
暗号化されたパスワードをバックエンドに渡します
バックエンドは、ユーザー アカウントを使用してユーザー情報を取得します
バックエンドは、暗号化されたパスワードに対して md5 暗号化を実行し (ソルトを削除し)、それを次のファイルに保存されているパスワードと比較します。データベース
一致する場合はログインが成功し、一致しない場合はログインが失敗します
3.1 .1: フロントエンド
const params = { ...this.ruleForm, sex: this.ruleForm.sex === '女' ? '0' : '1', //设置密码加密(加上固定salt值) password: md5(this.ruleForm.password + this.salt) } addEmployee(params).then(res => { if (res.code === 1) { this.$message.success('员工添加成功!') if (!st) { this.goBack() } else { this.ruleForm = { username: '', 'name': '', 'phone': '', password: '', // 'rePassword': '',/ 'sex': '男', 'idNumber': '' } } } else { this.$message.error(res.msg || '操作失败') } }
3.1.2: バックエンド
/** * 添加员工 */ @PostMapping public R<String> save(@RequestBody Employee employee){ //生成随机salt值 String salt = RandomStringUtils.randomAlphanumeric(5); //设置随机盐值 employee.setSalt(salt); //设置密码二次加密 employee.setPassword(DigestUtils.md5DigestAsHex((salt + employee.getPassword()).getBytes())); boolean save = employeeService.save(employee); if(save){ return R.success("添加成功!"); } return R.error("添加失败!"); }
3.2。 1: フロントエンド
const params = { ...this.loginForm, //登录密码加上固定盐值后发送 password: md5(this.loginForm.password + this.salt), } let res = await loginApi(params) if (String(res.code) === '1') { localStorage.setItem('userInfo', JSON.stringify(res.data)) window.location.href = '/backend/index.html' } else { this.$message.error(res.msg) this.loading = false }
3.2. 2: バックエンド
/** * 员工登录 */ @PostMapping("/login") public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){ //1.获取传输过来的加密后的密码值 String encryPassword = employee.getPassword(); //2.从数据库中获取用户信息 LambdaQueryWrapper<Employee> lqw = new LambdaQueryWrapper<>(); lqw.eq(Employee::getUsername,employee.getUsername()); Employee emp = employeeService.getOne(lqw); //3.如果没有查询到则返回登陆失败查询结果 if(emp == null){ return R.error("没有查询到该用户信息!"); } //4.获取注册时保存的随机盐值 String salt = emp.getSalt(); //5.将页面提交的密码password进行md5二次加密 String password = DigestUtils.md5DigestAsHex((salt + encryPassword).getBytes()); //6.密码比对,如果不一致则返回登陆失败结果 if(!emp.getPassword().equals(password)){ return R.error("密码错误!"); } //7.查看员工状态是否可用 if(emp.getStatus() == 0){ return R.error("该员工已被禁用!"); } //8.登录成功,将员工id存入Session对象并返回登录成功结果 request.getSession().setAttribute("employee",emp.getId()); return R.success(emp); }
以上がJava 二重 MD5 暗号化を使用して安全なログインを実現する方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。