취약한 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
package com.openeg.secolab.test.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class MissingAuthController {
@Autowired
BankAccountService bankAccountService;
@PostMapping(value = "/transfer")
public void sendBankAccount(@ModelAttribute("BankAccModel") BankAccModel sender, String recipientAccNumber, int amount) {
// 입력받은 계좌번호를 사용해 송금받는 사람의 계좌 정보를 조회합니다.
BankAccModel recipient = bankAccountService.getAccountInfo(recipientAccNumber);
bankAccountService.transfer(sender, recipient, amount);
}
}
class BankAccModel {
private int balance;
private String accountNumber;
public int getBalance() { return balance; }
public void setBalance(int balance) { this.balance = balance; }
public String getAccountNumber() { return accountNumber; }
public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; }
}
class BankAccountService {
@Autowired
AccountDAO dao;
public BankAccModel getAccountInfo(String recipientAccNumber) {
/* 입력받은 계좌번호를 이용해 DB에서 계좌 정보를 조회하여 반환합니다 */
return dao.selectAccount(recipientAccNumber);
}
public boolean transfer(BankAccModel sender, BankAccModel recipient, int amount) {
boolean result;
if (amount < 0 || amount > sender.getBalance()) {
// 이체 금액이 0보다 작거나, 보내는 사람 계좌의 잔고보다 크면 false 를 반환합니다.
System.out.print("계좌이체에 실패하였습니다.");
result = false;
} else {
sender.setBalance(sender.getBalance() - amount);
recipient.setBalance(recipient.getBalance() + amount);
System.out.print("이체한 금액: " + amount + "원");
System.out.print("받는 분 계좌번호: " + recipient.getAccountNumber());
System.out.print("잔액: " + sender.getBalance());
System.out.print("계좌이체에 성공하였습니다.");
result = true;
}
return result;
}
}
취약점 분석
1
bankAccountService.transfer(sender, recipient, amount);
해당 코드에서 실제 수정하는 사용자와 일치 여부를 확인하지 않고, 회원정보를 수정하고 있다. 적절한 인증과정 없이 중요정보를 열람 또는 변경 할 때 취약점이 발생할 수 있다.
회원정보를 수정하는 사용자와 로그인 사용자와 동일한지 확인하여 해당 취약점을 방지할 수 있다.
안전한 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
package com.openeg.secolab.test.controller;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class MissingAuthControllerSec_201 {
@Autowired
BankAccountService bankAccountService;
@PostMapping(value = "/transfer")
public void sendBankAccount(@ModelAttribute("BankAccModel") BankAccModel sender, String recipientAccNumber,
int amount, HttpSession session) {
// 서버의 세션에 저장된 사용자 정보로부터 사용자의 계좌번호를 가져오세요.
String senderAcc = (String) session.getAttribute("accountNumber");
// 로그인된 사용자의 계좌 정보와 이체하고자 하는 계좌 정보가 일치하는 경우에만 계좌 이체를 수행
if (senderAcc.equals(sender.getAccountNumber())) {
// 입력받은 계좌번호를 사용해 송금받는 사람의 계좌 정보를 조회
BankAccModel recipient = bankAccountService.getAccountInfo(recipientAccNumber);
bankAccountService.transfer(sender, recipient, amount);
} else {
System.out.println("사용자 정보와 계좌 정보가 일치하지 않습니다.");
}
}
}
class BankAccModel {
private int balance;
private String accountNumber;
public int getBalance() { return balance; }
public void setBalance(int balance) { this.balance = balance; }
public String getAccountNumber() { return accountNumber; }
public void setAccountNumber(String accountNumber) { this.accountNumber = accountNumber; }
}
class BankAccountService {
@Autowired
AccountDAO dao;
public BankAccModel getAccountInfo(String recipientAccNumber) {
/* 입력받은 계좌번호를 이용해 DB에서 계좌 정보를 조회하여 반환합니다 */
return dao.selectAccount(recipientAccNumber);
}
public boolean transfer(BankAccModel sender, BankAccModel recipient, int amount) {
boolean result;
if (amount < 0 || amount > sender.getBalance()) {
// 이체 금액이 0보다 작거나, 보내는 사람 계좌의 잔고보다 크면 false 를 반환합니다.
System.out.print("계좌이체에 실패하였습니다.");
result = false;
} else {
sender.setBalance(sender.getBalance() - amount);
recipient.setBalance(recipient.getBalance() + amount);
System.out.print("이체한 금액: " + amount + "원");
System.out.print("받는 분 계좌번호: " + recipient.getAccountNumber());
System.out.print("잔액: " + sender.getBalance());
System.out.print("계좌이체에 성공하였습니다.");
result = true;
}
return result;
}
}