될때까지

((TIL)) 프리온보딩 백엔드 사전스터디 : Node.js 5 본문

프로젝트/프리온보딩

((TIL)) 프리온보딩 백엔드 사전스터디 : Node.js 5

랖니 2022. 9. 27. 21:43
728x90

🔥 관심사의 분리와 레이어드 패턴 정리

    포스팅 참고

 

🔥 레이어드의 의존성 순서

app -> router -> controller -> service -> models 순으로 갈수록 데이터베이스의 접근에 가까워진다.
각 파일에서 export한 모듈들을 어떤 파일에서 require해서 사용하고 있는 지 흐름을 읽어보면 상위에서 하위 레이어로만 의존하는 걸 알 수 있다.

  • app.js : express app으로 서버를 생성한다. express app 인스턴스를 생성하고 필요한 미들웨어를 붙이는 로직이 들어간다.
  • routes : 라우팅 로직
  • controllers : http 요청에 따른 에러 핸들링 및 서비스 로직에서 데이터를 받아와 응답으로 내보낸다.
  • services : 컨트롤러에서 넘겨받은 인자로 다양한 비즈니스 로직을 처리해서 데이터로 접근하는 로직
  • models : 데이터베이스에 접근하기 위한 모델 dao가 정의되어 있는 곳

하위 모듈들은 의존성이 없이 그냥 여러 파일에서 사용될 수 있는 반복되는 로직을 분리해놓은 폴더다.

  • middlewares : 컨트롤러에 닿기 전에 반복되는 로직들을 넣어놓는다(인증/인가)
  • utils : 모든 레이어에서 자주 쓰이는 로직 (에러핸들링)
  • .env : 환경 변수
  • node_modules : 노드 패키지 모듈
  • .gitignore : 깃이 추적하지 않는 파일
  • package.json : 노드 모듈을 관리하는 파일

 

🔥 에러 발생시키는 2가지 방법

const isPasswordCorrect = bcrypt.compareSync(password, emailExistUser.password)  

if (!isPasswordCorrect) {
    // 방법1 - 직접 에러 throw하기
    console.log('INVALID_PASSWORD')
    throw new Error("INVALID_PASSWORD_ERROR")

    // 방법2 - 변수에 담기
    console.log('INVALID_PASSWORD')
    const err = new Error("INVALID_PASSWORD_ERROR")
    err.status = 400
    throw err
}

 

🔥 에러코드를 아래처럼 작성했던 이유

실제로 인턴쉽때 에러 핸들링 코드를 아래처럼 작성했었는데, 오늘에서야 '정확하게' 깨달았다. 

    return res.status(err.status || 500).json({ message : err.message || "SERVER_ERROR"});

레이어드 패턴에 따라서 구조를 나눠났기 때문에 req, res에 대한 처리는 controller에서만 할 수 있다. 비즈니스 로직을 처리하는 과정에서 에러를 발생하면, 위의 주제에서처럼 에러를 throw해서 넘겨줬다. 에러를 만나면 상위 객체로 전달하기 때문에, 서비스를 호출한 컨트롤러로 전달이 되고 컨트롤러에서 try, catch문을 작성했기 때문에 전달된 에러가 catch에서 err 이름으로 전달된다.

err.status || 500 이라는 코드를 작성했는데, 해당 코드에서 err.status가 없다면(컨트롤러에서 건네준 에러가 없다 => 없으면 없는 값을 호출해? undefined가 할당됨!!) falsy한 값이 된다. || or연산자는 첫번째 truthy한 값을 반환하기 때문에 err.status가 없는 값이라면 500을 반환하게 되는 코드였다.

 

🔥 SQL Injection

나쁜놈(음.. 해커? 의도하지 않는 사용자?)이 의도되지 않은 SQL문을 주입해서 데이터베이스에 비정상적인 동작을 하도록 조작하는 행위를 말한다. 노드 프로젝트에서 혼자서 작업할때는 sql 쿼리문을 아래와 같이 작성했었다.

`INSERT INTO 
    users 
    (korean_name, email, password, address, phone_number) 
VALUES 
    ('${user.korean_name}', '${user.email}', '${user.password}', '${user.address}', '${user.phone_number}');`;

위의 코드는 인젝션 공격당하기 딱좋은 코드였다^^.

sql문은 텍스트형식으로 전달되는데, 위처럼 작성했다면 텍스트 중에서 변수의 위치를 노출하게 된다. 해당 변수를 지우고 delete문을 삽입할 경우 코드가 정상 작동하며 DB의 모든 데이터를 날릴 위험이 있다.

따라서 이제부터는 변수를 직접 대입하지 말고 ? 물음표를 사용해 어디가 변수 자리인지 숨겨서 인젝션 공격을 대비해주자.

`INSERT INTO 
        users 
        (korean_name, email, password, address, phone_number) 
    VALUES 
        (?, ?, ?, ?, ?)`, [korean_name, email, password, address, phone_number];

 

728x90