
Juice Shop에는 로그인 창이 있습니다. 여기서 SQL Injection을 시도해 볼 수 있을 것 같습니다.
이메일 창에 ' or 1=1 -- 이라는 가장 간단한 SQLI 구문을 넣어보겠습니다.

로그인을 하니 admin 계정으로 로그인이 되고 Login Admin 문제가 풀렸습니다.
' or 1=1 -- 구문을 넣었을 때 SQL 쿼리가 아마 SELECT * FROM Users WHERE email = '' or 1=1 --' AND password = '1234' 처럼 변경되었을 것입니다.
여기서 email에는 아무것도 넣지 않았는데 어떻게 admin 계정으로 로그인이 된 것일까요?
이 쿼리는 데이터베이스에게 "Users 테이블에 있는 모든 회원 정보를 다 가져와!"라고 명령한 것과 같습니다. 데이터베이스는 수백 명의 회원 정보를 통째로 서버에 던져줍니다.
그런데 주스샵(그리고 대부분의 엉성하게 짜인 웹 서비스)의 로그인 코드는 보통 가져온 회원 정보 목록 중에 첫 번째 사람의 정보로 로그인을 시켜줍니다. 그리고 시스템을 구축할 때 가장 먼저 등록되는 계정은 보통 admin이기 때문에 admin 계정으로 로그인이 된 것입니다.
만약 admin의 이메일 계정 명을 알고 있다면 admin@example.com' or 1=1 -- 으로 타겟팅 SQL Injection을 수행할 수도 있습니다.
Coding Challenge를 풀어보겠습니다.

Find It의 정답은 당연히 SQL 쿼리 문입니다.
models.sequelize.query(`SELECT * FROM Users WHERE email = '${req.body.email || ''}' AND password = '${security.hash(req.body.password || '')}' AND deletedAt IS NULL`, { model: UserModel, plain: true })
전문은 다음과 같습니다. password는 security.hash로 해시 함수를 적용하여 SQL Injection을 막고 있습니다.
models.sequelize.query(`SELECT * FROM Users WHERE email = $1 AND password = $2 AND deletedAt IS NULL`,
{ bind: [ req.body.email, security.hash(req.body.password) ], model: models.User, plain: true })
해결 방법은 위와 같이 바인딩 매개변수를 사용해서 데이터베이스가 쿼리 구조를 먼저 파악하고 입력한 데이터를 후에 삽입하여 악의적인 특수 문자도 절대 명령어로 해석하지 않게 하는 것입니다.

사진처럼 match를 이용하여 필터링하는 방법은 여러 방법으로 우회하여 SQL Injection을 수행할 수 있으므로 바람직한 방법은 아니라고 합니다.