재우니 개발자 블로그

 

 

아래는 Secure Coding 실무에서 바로 적용하는 코드 중심 예시들이다.
언어 구분 없이 웹, API, DB, 파일 처리, 인증·암호화 등 실제로 사고가 많이 나는 포인트만 골라서 정리했다.
모두 “나쁜 코드 → 좋은 코드” 형태로 설명한다.


✅ 1. 입력 검증(Input Validation)

❌ 잘못된 예

// 사용자가 입력한 값을 그대로 사용
const id = req.query.id;
const sql = `SELECT * FROM Users WHERE Id = ${id}`;
db.query(sql);

 

 

 

✅ 안전한 예

// 숫자 검증 + 파라미터 바인딩
const id = parseInt(req.query.id, 10);
if (Number.isNaN(id)) return res.status(400).send('Invalid');

const sql = "SELECT * FROM Users WHERE Id = ?";
db.query(sql, [id]);

 

 

핵심 실무 포인트

  • 숫자는 parseInt, 문자열 길이/포맷 검증
  • SQL은 무조건 파라미터 바인딩
  • “검증 실패 = 요청 거절”이 기본 전략

✅ 2. SQL Injection 방지 (Prepared Statement 필수)

❌ 취약한 코드

var sql = "UPDATE Product SET Name = '" + name + "' WHERE Id=" + id;
db.Execute(sql);

 

 

✅ 안전한 코드 (Dapper)

var sql = "UPDATE Product SET Name = @Name WHERE Id = @Id";
db.Execute(sql, new { Name = name, Id = id });

 

실무 사투리 팁

  • “문자열 붙이면 끝장난다.”
  • Dapper, EFCore, JDBC, PDO, 무엇이든 바인딩이 기본기

✅ 3. XSS 방지 (출력 시 인코딩)

❌ 나쁜 예

<div>사용자 입력: {{ userInput }}</div>

 

 

✅ 안전한 예 (Vue/React 기본 escape 기능 활용)

<div>사용자 입력: {{ safeText }}</div>

 

또는 서버에서 직접 이스케이프:

var safe = System.Net.WebUtility.HtmlEncode(input);

 

실무 팁

  • XSS는 입력이 아니라 출력 시점에서 해결
  • 리치 텍스트 필요하면 “화이트리스트 필터링” 필요

✅ 4. 파일 업로드 (디렉토리 탈출 방지)

❌ 취약 코드

var path = "uploads/" + file.FileName;
await File.WriteAllBytesAsync(path, bytes);

 

 

❗ 공격 예

../../../web.config → 서버 파일 덮어쓰기

✅ 안전 코드

var safeName = Path.GetFileName(file.FileName); // 디렉토리 제거
var safePath = Path.Combine("uploads", safeName);
await File.WriteAllBytesAsync(safePath, bytes);

 

추가 보호

  • 확장자 화이트리스트 (.jpg, .png, .pdf)
  • 실행 가능한 파일 차단 (.exe, .aspx, .js)

✅ 5. 인증 토큰 저장 시 Secure 옵션

❌ 취약 쿠키

Response.Cookies.Append("Token", token);

 

 

✅ 보안 쿠키

Response.Cookies.Append("Token", token, new CookieOptions {
    HttpOnly = true,
    Secure = true,
    SameSite = SameSiteMode.Strict
});

 

실무 팁

  • HttpOnly: JS 탈취 방지
  • Secure: HTTPS 전송 강제
  • SameSite: CSRF 완화

✅ 6. 암호화 – 절대 직접 구현하지 말 것

❌ 직접 만든 암호화(실무에서 절대 금지)

string Encrypt(string s) {
    return Convert.ToBase64String(Encoding.UTF8.GetBytes(s)); // 암호화 아님
}

 

 

✅ 안전한 암호화 (AES-GCM 예시)

using var aes = Aes.Create();
aes.Mode = CipherMode.GCM; 
aes.GenerateKey();
aes.GenerateIV();

using var encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
var cipherText = encryptor.TransformFinalBlock(plainBytes, 0, plainBytes.Length);

 

 

실무 팁

  • AES-GCM / RSA / PBKDF2 등 검증된 알고리즘 사용
  • “직접 암호화 로직 설계”는 금지

✅ 7. 비밀번호 저장 (Hash + Salt)

❌ 나쁜 예

Password = SHA256('1234')

 

 

❗ 해시만 쓰면 rainbow table에 뚫린다

✅ 안전 예

  • PBKDF2
  • bcrypt
  • Argon2

C# 예시(ASP.NET Core 기본)

var hashed = passwordHasher.HashPassword(user, plainPassword);

 

 


✅ 8. 예외 메시지 노출 금지 (논리 정보 노출 방지)

❌ 위험한 예

catch (SqlException ex) {
    return BadRequest(ex.ToString()); // 내부 DB 정보 노출
}

 

 

✅ 안전한 예

catch {
    _logger.LogError("DB 오류 발생");
    return StatusCode(500, "Server Error");
}

 

 


✅ 9. 서버 사이드 요청 위조(SSRF) 방지

❌ 취약 예

var json = await http.GetStringAsync(userInputUrl);

 

 

✓ 위험: 내부망 접근, 메타데이터 API 접근 가능

✅ 안전 예

if (!Uri.TryCreate(url, UriKind.Absolute, out Uri? uri))
    return BadRequest();

var allowedSchemes = new[] { "http", "https" };
if (!allowedSchemes.Contains(uri.Scheme))
    return BadRequest("Invalid Scheme");

// 도메인 화이트리스트
var allowedHosts = new[] { "api.company.com" };
if (!allowedHosts.Contains(uri.Host))
    return BadRequest("Blocked Host");

var json = await http.GetStringAsync(uri);

 

 


🔥 종합 실무 요약

위험 방지 핵심

SQL Injection 파라미터 바인딩 필수
XSS 출력 인코딩
CSRF SameSite/CSRF 토큰
파일 업로드 파일명 정규화 + 확장자 제한
인증 HttpOnly + Secure 쿠키
비밀번호 bcrypt/PBKDF2/Argon2
예외 처리 내부 정보 숨기기
암호화 표준 알고리즘 사용