[JSTS-011][실무] 입력값을 확인해 안전한 JavaScript 만들기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[JSTS-011][실무] 입력값을 확인해 안전한 JavaScript 만들기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 82회 작성일 26-09-05 11:35

본문

[이번 수업]
웹 폼, URL, JSON처럼 프로그램 밖에서 들어온 값은 기대한 모양과 다를 수 있습니다. JavaScript에서 자료형, 허용 필드, 길이, 숫자 범위를 확인하고 검증된 값만 새 객체에 담는 방법을 배웁니다.

[선수지식]
JSTS-003의 객체, JSTS-007의 TypeScript 타입, BACK-005의 입력 검증을 알고 있으면 좋습니다.

[학습목표]
1. 신뢰 경계에서 입력 구조와 값을 검증합니다.
2. 허용 목록과 명시적 검사로 자동 형변환을 피합니다.
3. 브라우저 검증과 서버 검증의 역할을 구분합니다.

[핵심개념]
신뢰 경계는 브라우저, 파일, 외부 API처럼 신뢰 수준이 다른 곳에서 값이 넘어오는 지점입니다. 이곳에서 자료형 → 필수 필드 → 허용 필드 → 길이·범위 → 업무 규칙 순으로 확인합니다. 허용 목록은 받아도 되는 필드를 먼저 정하고 나머지를 거부하는 방식입니다. 통과한 값만 새 객체에 복사하면 뜻밖의 속성이 다음 계층으로 퍼지는 일을 줄일 수 있습니다.

JavaScript에서 "20"과 20은 다릅니다. Number.isInteger 같은 명시적 검사 없이 느슨한 비교나 자동 형변환에 기대지 않습니다. 문자열은 trim으로 공백을 정리한 뒤 빈 값과 최대 길이를 확인합니다. JSON.parse는 문법만 해석합니다. TypeScript 타입도 외부 JSON을 실행 중에 자동 검사하지 않으므로 별도 검증이 필요합니다.

브라우저의 required, minlength, min은 빠른 안내에 유용하지만 요청은 바뀔 수 있으므로 서버에서도 검사합니다. 검증은 안전한 출력의 대체가 아닙니다. 화면에는 신뢰하지 않은 문자열을 HTML로 조립하지 말고 textContent처럼 텍스트로 넣습니다. 데이터베이스에는 문자열 연결 대신 매개변수 방식의 API를 사용합니다.

[따라하기]
아래 코드를 validate.mjs로 저장합니다. 외부 패키지는 필요하지 않습니다.

const fail = (error) => ({ ok: false, error });

function validateProfile(input) {
  if (typeof input !== "object" || input === null || Array.isArray(input))
    return fail("object required");
  if (Object.keys(input).some((key) => !["name", "age"].includes(key)))
    return fail("unexpected field");
  if (typeof input.name !== "string") return fail("invalid name");
  const name = input.name.trim();
  if (name.length < 1 || name.length > 40) return fail("invalid name");
  if (!Number.isInteger(input.age) || input.age < 14 || input.age > 120)
    return fail("invalid age");
  return { ok: true, value: { name, age: input.age } };
}

console.log(JSON.stringify(validateProfile({ name: " Mina ", age: 20 })));
console.log(JSON.stringify(validateProfile({ name: "Mina", age: "20" })));

macOS, Linux, Windows PowerShell 모두 node validate.mjs로 실행합니다. 설치 여부는 node --version으로 확인하세요. 예상 결과는 {"ok":true,"value":{"name":"Mina","age":20}}와 {"ok":false,"error":"invalid age"}입니다. 문자열 "20"을 숫자로 몰래 바꾸지 않고 거부합니다.

[흔한 실수]
브라우저에서 막았으니 서버 검증이 필요 없다고 생각하지 마세요. typeof null은 object이므로 따로 거부합니다. 입력 객체 전체를 저장하거나 알 수 없는 필드를 조용히 받지 마세요. 검증과 안전한 HTML 출력을 같은 것으로 착각하는 것도 위험합니다.

[보안 주의]
본인 소유의 로컬·격리 환경과 가상 값으로만 실습합니다. eval이나 Function으로 입력을 실행하거나 사용자 문자열을 코드·명령·HTML로 이어 붙이지 않습니다. 요청 크기를 파싱 전에 제한하고 실제 비밀번호·토큰·개인정보를 오류나 로그에 남기지 마세요. 검증 도구는 공식 출처와 지원 버전을 확인합니다.

[직접 해볼 과제]
role 필드를 추가하되 reader 또는 editor만 허용하세요. role 누락, admin 입력, 올바른 reader 입력을 실행해 예상 결과와 비교합니다. 반환 객체에 허용한 세 필드만 있는지도 확인하세요.

[확인문제]
1. 허용 목록 방식은 어떤 입력을 받아들이나요?
2. TypeScript 타입이 있어도 외부 JSON을 실행 시 검증해야 하는 이유는 무엇인가요?
3. 브라우저와 서버에서 검증을 모두 해야 하는 이유는 무엇인가요?

[다음 학습]
다음 차례인 WEB-011에서 오프라인에서도 동작하는 PWA를 배웁니다. JSTS 트랙에서는 JSTS-012에서 검증과 테스트를 포함한 TypeScript 미니 서비스를 만듭니다.

[공식 참고 자료]
MDN 클라이언트 폼 검증
https://developer.mozilla.org/en-US/docs/Learn_web_development/Extensions/Forms/Form_validation
OWASP 입력 검증 지침
https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html
OWASP XSS 예방 지침
https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html
TypeScript 타입 지우기 설명
https://www.typescriptlang.org/docs/handbook/2/basic-types.html#erased-types

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
3,944
어제
6,862
최대
16,772
전체
769,895
Copyright © 소유하신 도메인. All rights reserved.