지난 금테코 기술 세미나에서 Django에 대해 간단히 발표하고 받은 질문에 대해 답변할 수 있게끔 추가적으로 조사하고 정리해보았다.
Django의 주요 기능 중 하나로 보안을 꼽았었는데, 구체적으로 어떠한 역할을 하는지에 대한 질문을 받았었다. 그래서 어떤 기능을 제공하는지 알아보았다.
Cross site request forgery (CSRF) 보호
CSRF 공격은 공격자가 타 사용자의 동의 없이 해당 사용자의 자격 증명을 사용할 수 있다.
Django는 대부분의 CSRF 공격에 대한 내장 보호기능을 가지고 있어서, 적절하게 사용하면 된다.
SQL 인젝션 방지
SQL 인젝션은 공격자가 데이터베이스에서 임의의 SQL 구문(개발자가 의도하지 않은)을 실행할 수 있는 공격이다. 데이터베이스의 레코드를 삭제하거나 누출할 수 있는 결과를 초래한다.
Django의 쿼리셋은 SQL로부터 안전한데, 쿼리 매개 변수화(query parameterization)을 사용하여 쿼리를 생성하기 때문이다.
쿼리의 SQL 코드는 쿼리의 매개변수와 분리되어 정의된다. 만약 매개변수가 유저에 의해 만들어져서 안전하지 않다면 기본 데이터베이스 드라이버에 의해 제거된다.
(물론 Django는 개발자에게 raw 쿼리를 작성하거나 custom sql을 실행할 수 있는 기능을 제공한다)
클릭재킹 방지
클릭재킹은 악의적인 사이트가 다른 사이트를 프레임으로 감싸는 공격이다. iframe 요소와 CSS를 교묘하게 이용하여 투명하게 만든 공격 대상 사이트를 함정 사이트와 겹쳐 사용자가 모르는 사이에 공격 대상 사이트의 기능을 클릭하도록 유도하는 공격 방법이다.
Django는 X-Frame-Options 미들웨어 형태로 클릭재킹 방지를 포함하며, 이것을 지원하는 브라우저에서는 프레임 안에 사이트가 렌더링 되는 것을 방지한다.
Host header validation
Django는 특정 경우 클라이언트가 제공하는 호스트 헤더를 사용하여 URL을 구성한다. 이러한 값들은 XSS 공격, CSRF를 위한 가짜 호스트 값, 캐시 중독(Cache Poisoning) 공격을 방지한다.
주의
Django는 우수한 보안 기능을 제공하지만, 어플리케이션을 적절하게 배포하고 웹 서버, 운영 체제 및 기타 구성 요소의 보안 보호를 활용하는 것이 중요하다.
또한 위에서 언급한 기능들이 모든 공격을 막아주는 것은 아니다.
때문에 Django에서 제공하는 보안 기능들은 어떤 것이 있는지, 그리고 각 기능들의 한계점에 대해 이해하는 것이 중요하다.
Security in Django
기술 세미나에서 Flask와의 차이점에 대한 질문을 받았는데, Flask에 대해 전혀 알지 못하여 정확한 답변을 하지 못하였다.
이번에는 Django와의 차이점에 대해서만 간단히 알아보았고, 다음에 기회가 된다면 Flask에 대해서도 다뤄보고자 한다.
모두 Python을 기반으로 만들어진 웹 프레임워크
Python이 가진 장단점을 공유한다.(ex. 많은 라이브러리, 인터프리터 언어의 단점 등)
디자인
Django는 Batteries-included, 기본적으로 많은 기능을 제공하고자 하는데, Flask는 Minimalistic, 최소한으로 기능을 제공한다. 다만, 기능의 확장이 어려운 것은 아니다.(오히려 기능의 확장이 유연하고 편리하다)
Flask는 코드가 약 27,000줄 정도의 가벼운 프레임워크
Flask는 직관적이며 간결하다. 때문에 개발자가 많은 부분을 손봐야만 하고, 보안 역시 개발자가 신경을 좀 더 써야 할 것이다. 하지만 가볍기 때문에 Minimalistic한 서버를 구축할 수 있다.
Django는 무거운 Full-stack 프레임워크
대신에 이미 제공되는 기능들이 많고, 이를 간단히 사용하는 것으로 많은 기능을 수행할 수 있다. 때문에 비교적 간편하게 서버를 구축할 수 있다.
ORM
Flask는 기본으로 제공되는 ORM이 없기 때문에 DB에 접근할 때 SQLAlchemy와 같은 라이브러리를 사용하여 접근해야하지만, Django는 기본적으로 제공하는 ORM이 아주 강력하다.
Django의 ORM을 스탠드얼론으로 따로 쓰는 경우도 있다고 한다.
속도
Flask가 더 빠르다고 하는데, 별로 차이가 없다고 한다.(30ms정도)
이미 두 프레임워크 모두 초대형 트래픽을 소화해내고 있으므로(Django는 인스타그램, Flask는 Pinterest), 크게 문제가 되지 않을 것이라 한다.
만약 속도와 관련한 이슈가 발생한다면, 프레임워크 자체의 문제라기보다는 환경 설정이나 아키텍쳐 설계의 문제인 경우가 많다고 한다.
Python이 느린 이유
- 인터프리터로 동작하는 스크립트 언어
컴파일러는 코드를 기계어로 번역해서 실행 가능한 파일을 미리 만들 수 있는 반면, 인터프리터는 필요할 때마다 코드를 번역하여 실행한다.
이 때문에 컴파일러를 사용하는 언어에 비해 인터프리터를 사용하는 언어가 느리다.- 동적 타입 언어
C++과 Java와는 다르게 Python은 변수의 타입을 알려주지 않아도 된다. 이는 런타임에 변수나 객체에 대한 자료형을 판단하는 처리가 존재하기 때문이다. 컴파일러를 사용하는 언어들은 컴파일을 끝내면 각 자료형에 대한 판단이 완료되기 때문에 런타임에 이러한 처리를 할 필요가 없다.
둘 중 어느 것이 더 좋다기보다는, 상황에 맞는 프레임워크를 사용하는 것이 바람직하다고 생각한다.
더 자세히 알아보고 싶다면
Django와 Flask 중 어떤 프레임워크를 사용해야 할지에 대해 잘 설명되어 있는 포스트가 있어 이를 참고하여 위 내용을 작성하였다.
언제 어떤 프레임워크를 사용할지에 대해서도 서술이 잘 되어있으므로 참고해보기 바란다.(링크)
Python은 기본적으로 하나의 스레드에서 실행된다. 코드를 병렬로 실행하기 위해서는 별도의 스레드를 생성해야만 한다.
그런데 Python은 인터프리터를 사용하기 때문에 특정 시점에 하나의 코드만을 실행하게 된다.(Global Interpreter Lock : 전역 인터프리터 락)
이 때문에 파이썬은 다중 CPU 환경에서 동시에 여러 코드를 병렬로 실행할 수 없으며, Interleaving 방식으로 코드를 분할하여 실행한다고 한다.
결국 Python에서도 멀티스레딩이 가능하므로 Django에서도 멀티스레딩이 가능하다.
Django에서는 일반적으로 Celery를 사용하여 멀티스레딩과 동일한 기능을 수행한다고 한다.(관련 stackoverflow 게시글)
GIL때문에 한번에 한 코드만 번역이 가능하다면, 멀티스레딩이 어떻게 이루어지는지 궁금하여 찾아보았다.
이는 stackoverflow에서 답을 구할 수 있었다.
위 글에서 일부분만 추려내자면 한 스레드가 완료될 때까지 GIL을 붙잡고 있을 필요가 없다고 한다. 필요에 따라 락을 획득하고 해제할 수 있으며, 이 때문에 병렬로 진행될 수는 없지만 동시에 진행될 수는 있다.
스레드가 GIL을 획득하는 조건도 조금씩 다르다.
CPU 바인딩된 계산을 하는 스레드
실행 중인 코드가 많고, 인터프리터를 사용해야하는 스레드는 GIL을 획득하여 다른 스레드가 동일하게 실행되지 않게 한다.
I/O 바인딩된 스레드
I/O가 완료될 때 까지 기다리는 시간이 많기에, 이러한 스레드는 GIL을 획득하지 않는다.
Python의 프로세스는 각각 인터프리터를 가지고 있으므로, 프로세스 내 각 스레드는 GIL을 형재자매(동일 프로세스 내 스레드들)과 경쟁하기만 하면 된다. 이 때문에 Python에서는 프로세스 기반 병렬화가 권장된다고 한다.
동시(Concurrency) vs 병렬(Parallelism)
동시와 병렬은 다르다.
- 동시
두 스레드 사이의 연산을 어느 한쪽이 끝나기 전에 끼워서(interleave) 다른쪽을 시작할 수 있다. 한꺼번에 두 스레드를 시작할 필요가 없다.- 병렬
동시에(한꺼번에) 시작할 수 있는 연산을 의미한다.
https://docs.djangoproject.com/en/3.1/topics/security/
https://blog.lxf.kr/2018-11-19---why-or-not-django/
https://rakjido.github.io/2020/11/17/Django-Overview
https://dingrr.com/blog/post/%EC%96%B8%EC%A0%9C-django%EB%A5%BC-%EC%96%B8%EC%A0%9C-flask%EB%A5%BC-%EC%82%AC%EC%9A%A9%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C
https://hitzi.tistory.com/31
https://mattsegal.dev/is-django-too-slow.html
http://pythonstudy.xyz/python/article/24-%EC%93%B0%EB%A0%88%EB%93%9C-Thread
https://m.blog.naver.com/PostView.nhn?blogId=kkrdiamond77&logNo=221204080534&proxyReferer=https:%2F%2Fwww.google.com%2F