WebSite 개발 로직 분석 - Tirrilee/TechTalk GitHub Wiki

WebSite 구현 로직

보안이 중요하거나 조금 더 고차원적인 웹사이트를 구현하고 싶어 로직을 분석하였습니다. ASP.NET .NET Framework 4.5 기반으로 구성되어있는 웹사이트를 분석하였기 때문에, .NET Framework 관련 용어가 있습니다. & 제가 보려고 만든 것이기 때문에 코드를 봐야 아는 부분이 있습니다. 이 부분은 저에게 문의해주시면 알려드리겠습니다!

Controller

Login

Login 시도 전 : Session 값을 보고 이미 Session이 존재하면 로그인한 사용자 이므로 Main Page로 이동

Login 로직 : ID와 PW가 맞는지 확인

- 실패
 1) Log에 기록 후 Login Page로 이동

- 성공
  1) Log에 기록
  2) Session을 저장
      > Procedure를 이용해서 저장 후 Session key값을 받아옴
      > Session Key 값은 랜덤한 4개의 숫자
      > 만약 랜덤한 4개의 숫자가 이미 존재한다면 폐기 처리
  3) Session을 암호화 하여 Cookie에 저장

Private Information 변경 시 SMS 전송 코드

  1. 이전의 전화번호 조회
  2. Masking Phone Number ( 010-****-1234)
  3. SMS Sending (api를 호출 - SMS 기능 관련한 방법은 찾아봐야함)

BaseController

Authentication, Log, Exception Handler가 이미 Class의 Validation으로 가지고 있어 Login 이후 사용자의 권한 체크를 할 때 유용하게 사용된다.

Authentication Filter

  1. Cookie에 있는 Session Key 값을 가져옴 > 암호화 된 Session Key 값을 복호화
  2. Session 정보 확인 > 정보를 이용하여 메뉴 접근 권한 파악 및 사용자 정보 파악
  3. Session에 사용자 정보 저장
  4. 메뉴 접근 권한은 ViewBag을 이용하여 Shared View파일에 보내지고 Shared View에서는 View Bag으로 받아온 메뉴만 사용자에게 나타내기 때문에 이외의 메뉴는 접근 불가능

만약 Session 값이 있지 않거나 DB에 없는 Session값이 있다면

  1. Session 삭제
  2. Cookie 삭제
  3. Login Page로 Redirection

** 여기서 생각해봐야할것! 만약에 AJAX면 Login Page Redirection이 맞는 방법일까? 당연히 아님! 따라서 AJAX인지 판단한 이후 AJAX는 오류 메시지를 전달 AJAX가 아니면 Error Page OR Login Page로 전달

Log Filter

  1. Session 정보를 가져옴
  2. Log에 기록

보통

  1. 어떤 메뉴에
  2. 어떤 주소로
  3. 어떤 메소드에 접근했고
  4. 무슨 아이피 였으며
  5. 사용자 이름은 무엇이고
  6. 그 날짜가 언젠지

를 로그로 기록합니다. Session 정보가 존재하지 않으면 Log에 기록하지 않음

+) Log는 파일에 기록하거나 NoSQL을 사용하는데 파일에 기록하는 것이 더 흔하다

Exception Handler

에러가 발생할 때마다 Log를 찍고 Critical한 Error의 경우 메일을 전송

암호화 방법

BlowFish Algorithm 사용

AntiCSRF

먼저 CSRF란?

Web Application의 취약점 중 하나로 사용자가 자신의 의지와 무관하게 공격자가 의도한 행동을 하여 특정 웹페이지를 보안에 취약하게 한다거나 수정, 삭제등의 작업을 하게 만드는 공격 방법

URI Pattern을 이용하여 접근할 수 없는 페이지를 오픈한다던지, 개발에 사용되지만 실제로는 사용되지 않는 샘플 페이지를 찾아내는 등의 방법을 이용하여 공격 패턴을 분석한다. 이후 여기서 나오는 취약점을 이용해 공개된 게시판이나 메일을 이용하여 사용자가 해당 링크를 열게 만든다.

예시) 만약 사용자 개인 비밀번호를 변경하는 주소 패턴이 url?cmd=user_password_update?user=admin?password=1234 라면 이러한 링크를 사용자의 메일로 XSS 형태로 보내고 메일을 읽으면 Password가 변경되게 하는 것이다. img의 경우 필터링 하지 않아 나무위키의 경우 <img src="https://namu.wiki/logout"/> 를 이용하면 로그아웃 되게 만들 수 있다.

방어!

ClientToken과 Server Token을 확인한다 웹브라우저의 Same Origin 정책으로 인해 자바스크립트에서 타 도메인의 쿠키 값을 확인/수정하지 못한다는 것을 이용해서 쿠키 값과 서버의 값이 다르면 인증되지 않았다는 것을 검증할 수 있다

ClientToken : 요청의 Header Token 값
ServerToken : Cookie의 Token

두 개의 값을 확인하여 ASP.NET MVC에서 CSRF 방지 에서 사용되고 있는 방식을 구현한다.

View

View단은 거의 Ajax를 데이터를 가져온다 Ajax가 같은 패턴을 이용하여 데이터를 가져온 다는 것을 활용해 Ajax 패턴을 고정화 시켜놓고 url. data 등만 변경하여 더욱 쉽게 Ajax를 사용할 수 있게 만들었다.

이 방법은 잡다한 Javascript 지식에 설명하였다.

List View

  • 로딩 전 함수 실행
$(document).ready(function () {
    //조회 조건 설정
    //파트너 리스트 바로 조회
    //검색 조건 설정
});
  • 조회 조건 설정

이전에 Search한 값이 Search TextBox에 남아있도록 설정

  • 리스트 조회

리스트를 조회해서 보여줌 (SearchValue가 있다면 Search를 한 이후)

  • 검색 조건 설정

검색 조건 또한 javascript으로 동적으로 처리해준다. 왜냐하면 DropDown List가 database에 있어서 그 걸 불러온 이후 <option></option> 을 모두 붙여 출력하기 때문이다. 그 로직을 잠깐 설명하자면 먼저 옵션을 붙일 값들을 Ajax를 이용해서 가져오고 CallBack 함수를 두면 CallBack으로 을 붙이는 함수로 이동하게 한다.

  • 검색

검색 버튼 클릭시 검색을 하는 기능 e.preventDefault(); : event를 지속시키지 않고 중지

  • 더보기

PageSize를 10~20개 (자기가 원하는 만큼) 더해가면서 프린트 한다


WebSite를 개발하는 데 필요한 모든 기능

Install package

  1. DB 연동
  • Sql Connection : MSSQL 연동
  • Mysql.data : Mysql 연동
  1. Dependency Injection
  • Ninject
    • MVC :
    • API :
  • Unity
    • MVC : Unity MVC, Unity
    • API : Unity WebApi, Unity

BackEnd

공통적으로 필요한 기능들과 자세하게 구현되어있는 것들은 그것들에 대한 설명을 적어놓았습니다.


Unity

  • Interceptor
  • Register Type

BaseController

BaseController에서는 Authorize, Log, Exception Handler를 구현합니다. BascController를 상속 받으면 BaseController를 자식 Class가 실행되기 전에 실행되면서 아래의 Filter를 실행시킵니다. Filter Attribute를 사용할 때에는 Attribute의 정확한 종류를 알아야합니다.


Authorize Filter

OnAuthorization
  1. Ajax요청과 Page 요청은 Error Page가 다르기 때문에 에러를 다르게 설정
  • Ajax 요청 오류 : 인증 실패 상태값 설정
  • Page 요청 오류 : 오류 페이지로 Redirect

오류가 나면

  1. 오류가 나면 세션 삭제
  • 세션 삭제 : Database에서 저장한 Session 정보 삭제, 정보 삭제 시 이유 저장
  • Cookie 만료 : (예) Expire date를 하루 전으로 돌림
  • 현재 Session 삭제 : Client 측의 Session
  1. 1번과 2번 과정 오류 시 Log저장
AuthorizeCore

정상 실행 시

  1. Cookie에 저장된 Session 정보를 조회 (Cookie에는 암호화가 되어 있음)
  2. Session Key 값 복호화
  3. Session 정보가 현재 Database에 있는 정보와 일치하는지 확인
  4. Menu 조회 (권한에 따라 접근하는 메뉴가 달라짐)
  5. 관리자 정보 생성
  6. 기존의 Session 정보 삭제 & 새로운 로그인 정보 Session 저장

오류가 나면

  1. 정상 실행 과정 오류시 Log 저장
  2. 중간에 오류가 날 경우 string에서 이유를 저장
ExecuteResult

로그인 페이지로 영구 Redirection 수행

  1. Session에서 정보를 가져오지 못하면 Login페이지
  2. 가져온다면 Main Page로 가져옴

Logging Filter

OnActionExecuted

Action Log를 처리하는 기능

  1. 관리자 Session 정보 조회
  • Session 정보가 Null이면 오류 return
  1. 요청 데이터 가져오기 : Get인지 Post인지 확인
  2. 요청 데이터가 존재할 경우 Log에 저장할 정보 생성
  3. 관리자 로그 등록 (계정 아이디, 계정 ip, 메뉴 경로, 함수 이름, 로그 암호화)

ExceptionHandle Filter

OnException
  1. 어느 Controller와 Method에서 가져왔는지 분석
  • Ajax 요청일 경우 오류 Json Return
  • Page 요청일 경우 오류 Page Return (Status Code를 정확히 넣고)
  1. 상세 오류의 경우 Log에 저장하고 Mail로 전송

위의 Filter를 모두 수행한 다음에는 BaseController로 들어옵니다.

  1. AntiClickJackCss, AntiClickJackScript를 가져옴 (누를 것들 혹은 누르지 않을 것들을 미리 정의 )
OnActionExecuting

Action 처리 전 실행부

  1. 인증 필터를 거쳐 사용자 정보가 Session에 저장되어 있는 경우 해당 정보를 Contoller 또는 View에서 사용할 수 있도록 설정
    • Session 정보 가져옴
    • Ajax가 아니면 Page에서 Menu도 설정해줘야하기 때문에 Menu 재설정
OnActionExecuted

Action 처리 후 실행부


LoginController

Index
  1. 이미 로그인이 된 경우 Main으로 Redirect : Session이 Null이 아닐때
RequestLogin
  1. 이용자 정보 조회 : DB에서 정보를 얻고 정보가 맞는지 확인
  2. Cookie 생성
  • Value : SessionKey 값을 암호화
  • Expires : 30일 뒤
  • Path : 경로 (선택)

AntiCSRF Filter Attribute

  1. Token 가져오기
  • ClientToken 가져오기 (Header)
  • ServerToken 가져오기 (Cookie)
  1. Token 값 null인지 확인
  • null이라면 log 찍기
  • Ajax와 Page 요청은 다름
  1. AntiForgery라는 static class를 이용하여 (기존에 존재) Validate 확인

ModelVaerification

  1. ModelState 값 가져오기
  2. ModelState가 IsValid 값인지 확인
  • Ajax와 Page 다르게 오류 처리

다른 기능 정리

  • Config File

: 실행파일로 넣음 (사람들이 까볼 수 없게)

Google API Key와 같은 보안이 필요한 곳에 사용

  • Error Page View

; 404 Error, Internal Error 등을 표시해주는 페이지

  • Encryption, Decryption

: 암호화, 복호화를 해주는 함수

  • Constants

    • Error Code & Message 정의
    • Cookie, Session Information
    • URL 정의 (Default Page URL 정의 & Page URL, AJAX URL 다르게 정의)
    • Success Code는 0000 (Is Success Code 함수)
    • 정규식 정의
  • Enum

    • 사용자 타입별로
    • 메뉴 별로
    • 사용자 권한 별로
    • Date Type ("yyyyMM","yyyyMMdd" 등)
  • Util

    • 공통 함수 정의 (기본적인 함수 ex)Convert, Byte 등)
  • ModelVerification (Model Validation)

  • Ajax 공통 파일


Database

Account

  • Account Id
  • ID
  • Password : 암호화
  • SecurityCode
  • LastLoginDate
  • LastLogin Ip
  • PWD Update date
  • UserFlag
  • Register Date
  • Update Date

Admin

  • AdminNo
  • Account No
  • GradeNo
  • Name
  • PhoneNo
  • Email
  • UserFlag- RegisterDate
  • UpdateDate

LoginSession

  • SessionKey
  • AccountNo
  • IP Address
  • Login date
  • Access date

LoginFailHistory

  • SequenceNo
  • TryDate
  • AccountNo
  • ID
  • TryCount
  • IPAddress
  • ErrorCode
  • ErrorMessage
  • RegisterDate

SiteMenuAccessLog

  • SequenceNo
  • MenuNo
  • SiteTypeCode
  • MenuPath
  • MethodName
  • LogDesc
  • LogYMD
  • LogHash
  • RegisterDate

Site Menu

  • MenuNo
  • MenuGroupNo
  • MenuName
  • MenuDesc
  • MenuSortNo
  • MenuPath
  • MenuSegment
  • UserFlag
  • RegisterDate
  • UpdateDate

FrontEnd


C#

  • BundleConfig

JavaScript

  • ready : 페이지 로딩 때 실행되는 함수

JQuery

  • Ajax : Ajax 공통 함수 정의
  • Modal
  • Config : Server Information

Render

  • Styles.Render : css 파일 Rendering
  • Scripts.Render : js 파일 Rendering
  • Javascript는 정의되어있으면 가져오기
@if (IsSectionDefined("CustomJavascript"))
{
   @RenderSection("CustomJavascript");
}
  • @Html.AntiForgeryToken() 를 넣어 CSRF 방지

필수

  • Clean Code를 위해 Naming 정책
  • 주석 (Copyright)
  • summary
  • 공통적인 기능을 가진 것은 최소화
  • 공통적으로 쓰이는 부분은 묶어서
  • 기능을 최소한으로 쪼개서
  • sudo code를 짰을 때 그 sudo code처럼 실행되도록
  • Interface는 구현할 때 확장성을 생각하고 구현해야한다.
  • 주석을 달지 않아도 될만큼의 Naming
⚠️ **GitHub.com Fallback** ⚠️