>Java >java지도 시간 >Java 이중 MD5 암호화로 보안 로그인을 달성하는 방법

Java 이중 MD5 암호화로 보안 로그인을 달성하는 방법

WBOY
WBOY앞으로
2023-05-17 17:31:351338검색

One: 문제 소개

데이터베이스에 저장된 비밀번호를 해독합니다:

Java 이중 MD5 암호화로 보안 로그인을 달성하는 방법

Java 이중 MD5 암호화로 보안 로그인을 달성하는 방법

내 비밀번호가 성공적으로 해독된 것을 볼 수 있습니다. 이는 저를 놀라게 했습니다. MD5 알고리즘은 되돌릴 수 없기 때문입니다. 이는 해시 함수이며 해시 알고리즘을 사용합니다. 계산 과정에서 원본 정보의 일부가 손실됩니다. 그러면 왜 내 비밀번호가 웹사이트에서 해독될 수 있나요?

몇번의 검색 끝에 온라인 복호화 도구의 복호화 원리는 매우 간단하다는 것을 알았습니다. 원칙은 사용자가 일반적으로 사용하는 간단한 비밀번호를 수집하여 비밀번호 사전을 만든 다음 사전에 있는 비밀번호를 MD5로 암호화하여 저장하는 것입니다. 소위 "해독"할 때 실제 사용자 비밀번호 암호화의 암호문을 저장된 암호와 비교합니다. 암호문이 사전에 있으면 "해독"될 수 있습니다. 따라서 단순히 MD5를 사용하여 사용자 비밀번호를 암호화하는 것은 안전하지 않습니다. 비밀번호를 설정할 때 일반적으로 보안상의 이유로 비밀번호에는 영어 숫자 등이 포함되어야 합니다.

복호화 원리를 알고 나면 "복호화"가 가능한지 확인하기 위해 더 복잡한 비밀번호를 시도합니다. 먼저 비밀번호 "qweasd666"을 암호화합니다.

Java 이중 MD5 암호화로 보안 로그인을 달성하는 방법

암호화 후 32자리 소문자 암호문을 선택합니다. 복호화 작업:

Java 이중 MD5 암호화로 보안 로그인을 달성하는 방법

복호화 실패는 일치 및 크래킹을 위해 일반적으로 사용되는 암호문을 수집하는 것이 원칙임을 나타냅니다. "qweasd666" 비밀번호는 크랙이 불가능하므로 안전하며 모두 이 비밀번호를 사용하시면 됩니다(doge).

본론으로 돌아가서, 이 웹사이트는 내가 신중하게 설정한 비밀번호를 성공적으로 해독했고, 이로 인해 나는 매우 불안감을 느꼈고 로그인 보안 수준을 향상시켜야 한다고 느꼈습니다.

위에 언급한 암호 해독 작업 외에도 또 다른 큰 문제는 프런트 엔드가 데이터를 전송할 때 http가 일반 텍스트 전송을 사용한다는 것입니다. 전송 데이터 패킷이 가로채면 백엔드에 있는 암호화 알고리즘이 아무리 많아도 마찬가지입니다. 복잡하므로 귀하의 비밀번호는 다른 사람에게 알려지게 됩니다.

둘: 해결책

2.1: 첫 번째 암호화

문제를 찾은 후 올바른 약을 처방할 수 있습니다. 우선 http 일반 텍스트 전송 문제를 해결해야 한다고 생각합니다. 왜냐하면 이 위험이 가장 크고 일반적이기 때문입니다. 패킷 캡쳐로 캡쳐할 수 있는데 비밀번호 알아내기 무섭지 않나요? 일반 텍스트 전송에는 보안 문제가 있으므로 암호화를 통해 전송 보안을 보장할 수 있습니다

저는 여전히 MD5 암호화 방식을 사용하지만 비밀번호를 암호화하기 전에 고정된 솔트 값을 추가합니다. 소금? 소금을 넣는 건가요? 사실은 '조미료'를 조금 더 넣는다는 표현이 더 맞을 것 같습니다. 기본 아이디어는 다음과 같습니다. 사용자가 처음으로 비밀번호를 제공할 때(보통 등록 시) 프로그램은 개발 부담을 줄이기 위해 비밀번호에 일부 "소스"를 뿌립니다. 그런 다음 이 양념은 모든 사용자에게 동일합니다. 다시 해시합니다. 이렇게 하면 전송 중에 일반 텍스트 비밀번호가 유출되는 것을 방지할 수 있습니다.

2.2: 2차 암호화

참고로 제가 위에서 언급한 것은 일반 텍스트 비밀번호의 유출을 방지하기 위한 것이지만, 이것이 http나 데이터베이스를 통해 전송된 암호화된 비밀번호를 해커가 가로채더라도 암호문이 유출되지 않는다는 의미는 아닙니다. 해커는 유출이 발생하고 암호화된 비밀번호를 훔칩니다. 해커는 프런트엔드 js 파일을 파싱하여 프런트엔드 고정 솔트 값을 획득합니다. 그러면 해커는 레인보우 테이블을 통해 역질의를 수행하여 해당 값을 얻을 수 있습니다. 원래 비밀번호. 이때 2차 암호화의 중요성이 나옵니다. 2차 암호화의 구현 원리는 프런트 엔드에서 전달된 암호화된 비밀번호를 임의의 Salt 값과 결합한 후 암호화하는 것입니다(이번에는 임의의 솔트입니다). 값은 사용자가 로그인할 때 무작위로 생성되어 데이터베이스에 저장됩니다.

이때, 처음에 했던 것과 같은 의문이 드실 수 있는데, 즉 랜덤 솔트 값을 데이터베이스에 저장해 두었는데, 데이터베이스가 유출되면 랜덤 솔트 값은 어떻게 될까요? 해커가 암호화된 데이터를 복호화하고 솔트 값을 제거하면 비밀번호를 알아내는 것이 가능하지 않을까? 예, 해커가 그러한 수단을 통해 비밀번호를 얻는 것이 가능하지만, 이를 해독할 수 있는 경우에만 가능합니다. 당신이 알아야 할 것은 MD5는 직접 크랙할 수 없으며 철저한 방법을 통해서만 해독될 수 있다는 것입니다. 해커가 데이터베이스에서 암호화된 비밀번호를 알아냈지만 백엔드 암호화 과정을 알지 못한다면, 해커가 암호화 과정을 동시에 알고 있더라도 2차 솔팅으로 인해 이를 파싱할 수 없게 됩니다. 암호화된 데이터의 복잡성이 증가함에 따라 크래킹 비용이 기하급수적으로 증가하므로 이때의 암호문은 파싱하기가 어렵습니다. 시도 해봐. 물론 꼭 앞부분이나 끝부분에 소금을 넣을 필요는 없고 중간에 넣거나 따로 넣거나 역순으로 넣을 수도 있다. 프로그램 설계 시 유연하게 조정할 수 있어 난이도가 기하급수적으로 높아질 수 있다. 열분해.

2.3: 특정 구현

2.3.1: 사용자 등록

  • 프런트 엔드는 사용자가 입력한 비밀번호(고정 솔트)에 대해 md5 암호화를 수행하고

  • 암호화된 비밀번호를 백엔드에 전달합니다

  • 끝은 무작위로 솔트를 생성합니다

  • 생성된 솔트를 이용해 프런트엔드에서 전달된 비밀번호를 암호화한 후, 암호화된 비밀번호와 솔트를 함께 db에 저장합니다

2.3.2: 사용자 로그인

  • 프런트엔드에서 사용자에게 입력된 비밀번호는 md5 암호화(고정솔트)

  • 암호화된 비밀번호는 백엔드로 전달됩니다

  • 백엔드는 사용자 계정을 사용해 사용자 정보를 검색합니다

  • 백엔드 암호화된 비밀번호에 대해 md5를 수행하고(솔트 제거) 데이터베이스에 저장된 비밀번호와 비교합니다.

  • 일치하면 로그인이 성공하고, 그렇지 않으면 로그인이 실패합니다.

세 가지: 코드 구현

3.1: 첫 번째 암호화

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: 두 번째 암호화

3.2.1: 프런트엔드

const params = {
    ...this.loginForm,
    //登录密码加上固定盐值后发送
    password: md5(this.loginForm.password + this.salt),
}
let res = await loginApi(params)
if (String(res.code) === &#39;1&#39;) {
    localStorage.setItem(&#39;userInfo&#39;, JSON.stringify(res.data))
    window.location.href = &#39;/backend/index.html&#39;
} 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 yisu.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제