2020년 3월 25일 보안정보 스크래핑

2020년 3월 25일 보안정보 스크래핑 3월 25일 보안정보 스크래핑 ==================================================================== + 주요 취약점 - 메일전송 프로토콜을 이용한 원격 명령어 실행 주의 권고 외 1건 1. 메일전송 프로토콜을 이용한 원격 명령어 실행 주의 권고 최근 OpenSMTPD* 취약점이 발견되는 등 메일전송 프로토콜에서 원격 명령어 실행이 가능하여 주의를 권고함 공격자는 취약점을 악용하여 피해를 발생시킬 수 있으므로, 해결방안을 참고하여 조치 필요 - https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=35302 2. Django 제품 SQL Injection 취약점 보안 업데이트 권고 최근 Django*에서 SQL Injection취약점(CVE-2020-9402)을 악용할 수 있는 개념증명코드(Proof of concept, PoC)가 인터넷상에 공개되어 사용자의 보안 업데이트 필요 - https://www.krcert.or.kr/data/secNoticeView.do?bulletin_writing_sequence=35301 ==================================================================== + 취약점 - Apple Safari 취약점 1. Apple Safari 취약점 Apple Safari security bypass CVE-2020-3885 - https://exchange.xforce.ibmcloud.com/vulnerabilities/178339 Apple Safari security bypass CVE-2020-3887 - https://exchange.xforce.ibmcloud.com/vulnerabilities/178338 Apple Safari inform

Django 튜토리얼

Django 튜토리얼

설치하기

Python 3 설치

System에 파이썬3이 설치되어 있어야 한다.

$ python3 --version python 3.6.x

가상환경(virtualenv) 구축

장고걸스 프로젝트에서만 구동될 라이브러리로 구성할 것이기 때문에 파이썬 가상환경을 만든다.

$ mkdir djangogirls $ cd djangogirls $ python3 -m venv myvenv

Django란?

파이썬으로 만들어진 무료 오픈소스 웹 애플리케이션 프레임워크이다.

웹사이트를 구축할 때, 비슷한 유형의 요소들이 항상 필요하다. 에컨데 회원가입, 로그인, 로그아웃과 같이 사용자 인증을 다루는 방법이나 웹사이트의 관리자 패널, 폼, 파일 업로드와 같은 기능이 있다.

장고는 이러한 다시 발명해야 하는 문제로부터 해방감을 주는 웹 프레임워크 중 하나이다.

기본 동작

웹 서버에 요청 urlresolver 동작 - 패턴 목록과 URL과 맞는지 대조 후 일치하면 해당 요청을 view에 넘김 view에서 요청된 행동을 처리하고 그에 맞는 답장을 생성함 장고는 이 답장을 사용자 웹 브라우저에 전달

Django 시작

장고의 기본 골격을 만들어주는 스크립트를 실행한다. 기본적으로 장고에서 디렉터리와 파일명이 매우 중요하고 마음대로 변경하고 옮겨서는 안된다.

(myvenv) ~/djangogirls$ django-admin startproject mysite .

점 '.'은 현재 디렉터리에 장고를 설치하라고 스크립트에 알려주기 때문에 반드시 기입한다.

django-admin은 스크립트로 아래와 같이 디렉터리와 파일들을 생성한다.

djangogirls ├───manage.py └───mysite settings.py urls.py wsgi.py __init__.py

manager.py : 사이트관리를 도와주는 스크립트. 이 스크립트로 다른 설치 작업 없이, 컴퓨터에서 웹 서버를 시작할 수 있다.

settings.py : 웹 사이트 설정이 있는 파일

urls.py : urlresolver가 사용하는 패턴 목록을 포함하고 있다.

초기 설정

mysite/setting.py에서 초기설정을 한다.

DEBUG = True ALLOWED_HOSTS = ['*'] # 추후 PythonAnywhere에 배포할땐 적절히 변경 ... LANGUAGE_CODE = 'ko-kr' TIME_ZONE = 'Asia/Seoul' ... STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static')

데이터베이스 설정

mysite/setting.py에서 설정한다.

DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } }

디비를 초기화 한다.

$ python manage.py migrate

서버를 구동한다.

$ python manage.py runserver

장고 모델

장고 안의 모델은 객체의 특별한 종류이다. 이 모델을 저장하면 DB에 저장이 되는것이 특징이다.

애플리케이션 만들기

아래 명령어로 'blog'라는 프로젝트 내부에 별도의 애플리케이션을 만든다.

$ python manage.py startapp blog

구조는 아래와 같아 진다.

djangogirls ├── mysite | __init__.py | settings.py | urls.py | wsgi.py ├── manage.py └── blog ├── migrations | __init__.py ├── __init__.py ├── admin.py ├── models.py ├── tests.py └── views.py

애플리케이션 생성 후 장고에 앱을 시작했다고 setting.py를 통해 알려준다.

INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'blog', ]

블로그 글 모델 만들기

모든 Model 객체는 models.py 파일에 선언하여 모델을 만든다.

from django.db import models from django.utils import timezone class Post(models.Model): # 모델을 정의 author = models.ForeignKey('auth.User', on_delete=models.CASCADE) # title = models.CharField(max_length=200) text = models.TextField() created_date = models.DateTimeField( default=timezone.now) published_date = models.DateTimeField( blank=True, null=True) def publish(self): self.published_date = timezone.now() self.save() def __str__(self): return self.title

데이터베이스에 모델을 위한 테이블 만들기

장고에 생성한 모델을 먼저 적용 시킨다.

$ python manage.py makemigrations blog Migrations for 'blog': blog/migrations/0001_initial.py: - Create model Post

실제 디비에 모델 추가를 반영한다.

$ python manage.py migrate blog Operations to perform: Apply all migrations: blog Running migrations: Rendering model states... DONE Applying blog.0001_initial... OK

장고 관리자

방금 모델링 한 글들을 관리자에서 추가, 수정, 삭제가 가능하다.

관리자 페이지에서 만든 모델을 보려면 admin.site.register(Post)로 모델을 등록해야한다.

admin.py를 아래와 같이 수정

from django.contrib import admin from .models import Post admin.site.register(Post)

슈퍼 사용자(superuser) 생성

$ python manage.py createsuperuser

장고 urls

장고는 URLconf를 사용하여 장고에서 URL과 일치하는 뷰를 찾기 위한 패턴들의 집합이다.

urls.py에서 URL의 패턴을 검출해 view로 넘겨준다.

예컨데 홈페이지는 아래와 같이 만든다.

from django.contrib import admin from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # 기존 admin페이지 주소 path('', include('blog.urls')), # 홈페이지 주소 추가 ]

현재 장고는 localhost:8000/로 접속 요청을 blog.urls 로 전송해 추가 명령을 찾게 된다.

blog.urls

blog/urls.py라는 새 파일을 생성 후 수정한다.

from django.urls import path from . import views urlpatterns = [ path('', views.post_list, name='post_list'), ]

post_list라는 view가 루트 URL에 할당이 되었고, 장고에서 누군가가 접속했을때 views.post_list를 보이게 한다.

마지막 name='post_list' 는 URL에 이름을 붙인 것으로 뷰를 식별한다. 이름을 붙인 URL은 프로젝트 후반에 사용한다.

장고 view

뷰(View)는 애플리케이션의 "로직"을 넣는 곳이다. 뷰는 모델에서 필요한 정보를 받아와서 템플릿에 전달하는 역할이다.

blog/views.py

from django.shortcuts import render def post_list(request): return render(request, 'blog/post_list.html', {})

이 함수는 request 요청을 넘겨받아 render메서드를 호출하여 받은 템플릿(blog/post_list.html) 템플릿을 보여주게 된다.

HTML

템플릿은 blog/templates/blog 디렉터리에 저장된다. 그러므러 디렉터리 생성 후 마지막에 post_list.html파일까지 생성해준다.

장고 ORM과 쿼리셋(QuerySets)

쿼리셋은 전달받은 모델의 객체 목록이다. 디비로부터 데이터를 읽고 필터를 걸거나 정렬을 할 수 있다.

아래는 예제이다.

from blog.models import Post from django.contrib.auth.models import User Post.objects.all() # 전체 게시글 목록 쿼리셋 me = User.objects.get(username='admin') # 유저명이 admin인 사용자를 가져옴 Post.objects.create(author=me, title='Sample title', text='Test') # 객체 생성 Post.objects.filter(author=me) # admin 사용자가 작성한 게시글 목록으로 필터 Post.objects.filter(title__contains='title') # 'title' 이라는 글자가 포함된 제목의 글들 필터 from django.utils import timezone Post.objects.filter(published_date__lte=timezone.now()) # 현재시간보다 적은 published_date 값의 게시글로 필터 Post.objects.order_by('created_date') # 생성일 오름차순으로 정렬 Post.objects.order_by('-created_date') # 생성일 내림차순으로 정렬 Post.objects.filter(title__contains='title').order_by('created_date') # 쿼리셋 연결

템플릿에 동적 데이터 적용

Post모델은 models.py에, post_list모델은 views.py에 있다.

뷰는 기본적으로 모델과 템플릿을 연결하는 역할을 한다. post_list를 뷰에서 보여주고 이를 템플릿에 전달하기 위해서 모델을 가져와야 한다. 일반적으로 뷰가 템플릿에서 모델을 선택하도록 만들어야 한다.

아래와 같이 views.py를 수정한다.

from django.shortcuts import render from django.utils import timezone # 쿼리셋 필터를 위한 import from .models import Post # 우리가 생성한 모델을 가져옴 def post_list(request): posts = Post.objects.filter(published_date__lte=timezone.now()).order_by('published_date') # 쿼리셋 return render(request, 'blog/post_list.html', {'posts': posts}) # 매개변수 posts를 추가하여 보낸다.

장고 템플릿

장고는 데이터를 동적으로 보여주기위해 템플릿 태그라는 유용한 기능을 사용한다.

이전의 'posts' 라는 변수를 템플릿에 넘겼고 이를 템플릿에서 받기위해서는 기존 post_list.html 파일에 아래와 같이 데이터를 넣어본다.

Django Girls Blog {% for post in posts %} published: {{ post.published_date }} {{ post.title }} {{ post.text|linebreaksbr }} {% endfor %}

위처럼, html 코드안에서 파이썬코드를 실행하고 데이터를 활용하여 동적으로 화면에 출력할 수 있다.

템플릿 확장

기본 템플릿은 웹사이트 모든 페이지에 가장 기본틀이 되는 템플릿이다. 이런 디자인은 모든 페이지마다 소스를 붙여가며 사용할 필요는 없다. 또한 모든 파일을 수정할 필요없이 base가 되는 템플릿을 수정하면 모든 페이지에 적용되어 스마트하게 사용되어야 한다.

post_list.html 파일의 경로에 base.html 파일을 추가하고 기존 내용을 넣고 아래와 같이 수정한다.

{% load static %} Django Girls blog Django Girls Blog {% block content %} {% endblock %}

기존 post_list.html은 아래와 같이 변경한다.

{% extends 'blog/base.html' %} {% block content %} {% for post in posts %} {{ post.published_date }} {{ post.title }} {{ post.text|linebreaksbr }} {% endfor %} {% endblock %}

이렇게 block 과 extends 을 템플릿에 적절히 사용하면 앞으로 생성될 템플릿도 주요된 내용만 바뀌고 기본 템플릿은 적용되는 형태로 작업할 수 있다.

애플리케이션 확장

템플릿에 동적 링크 만들기

기존 정적으로 되어있는 링크를 아래와 같이 변경한다.

{{ post.title }}

위의 post_detail는 뷰 경로를 뜻한다.

pk = post.pk에서 pk는 데이터베이스의 각 레코드를 식별하는 기본키(Primary Key)의 줄임말로, Post모델에서 기본키를 지정하지 않았으므로 장고에서 pk라는 이름으로 필드를 추가하였다. 게시글이 추가될때마다 이 키값은 1,2,3 등으로 증가한다.

현재 post_detail이 구현이 되지않았기 때문에 post_list를 구현한것처럼 진행한다. 먼저 urls.py를 수정한다.

from django.urls import path from . import views urlpatterns = [ path('', views.post_list, name='post_list'), path('post//', views.post_detail, name='post_detail'), # post/정수값/ 에 해당하는 모든 url은 post_detail 뷰로 전송한다. ]

위처럼 views.post_detail이라는 뷰를 post_detail이라고 이름을 붙였고 URL법칙을 만들었다. 이는 장고가 post_detail이라는 이름을 해석할때, blog/views.py 파일 내부의 post_detail 이라는 뷰 함수로 이해하도록 해준다.

이제 views.py에 post_detail을 추가한다.

from django.shortcuts import render, get_object_or_404 def post_detail(request, pk): post = get_object_or_404(Post, pk=pk) return render(request, 'blog/post_detail.html', {'post': post})

장고 폼

장고 폼으로 강력한 인터페이스를 만들고 양식을 만들어, ModelForm을 생성해 자동으로 모델에 결과물을 저장할 수 있다.

최상위 blog 디렉터리에서 forms.py파일을 생성하고 아래와 같이 수정한다.

from django import forms from .models import Post class PostForm(forms.ModelForm): # 우리가 만들폼이 ModelForm이라고 지정함 class Meta: model = Post # 이 폼을 만들때 어떤 모델이 쓰이는지 지정함 fields = ('title', 'text',) # 이 폼에서는 title, text만 보여지게 만듬

URL

base.html에는 기능을 위해 post_new라는 이름으로 링크를 추가한다.

post_new 생성을 위해 blog/urls.py에 아래와 같이 추가한다.

from django.urls import path from . import views urlpatterns = [ path('', views.post_list, name='post_list'), path('post//', views.post_detail, name='post_detail'), path('post/new/', views.post_new, name='post_new'), ]

blog/views.py도 post_new가 동작하도록 아래와 같이 추가한다.

이때, 장고에서 폼을 제출할때에는 같은 뷰를 불러온다. 이때 request에는 우리가 입력했던 데이터들을 가지고 있는데, request.POST가 이 데이터를 가지고 있다. 그래서 아래와같이 조건문을 사용하여 구현한다.

from .forms import PostForm from django.shortcuts import redirect def post_new(request): if request.method == "POST": form = PostForm(request.POST) # POST로 받은 데이터를 PostForm으로 넘겨줌 if form.is_valid(): # 폼에 입력된 값이 올바른지 검사 post = form.save(commit=False) # 폼 저장, commit=False로 넘겨진 데이터를 바로 Post모델에 저장하지 않음. 작성자를 추가한 다음 저장해야 하기 떄문. post.author = request.user post.published_date = timezone.now() post.save() # 변경사항을 유지한다. return redirect('post_detail', pk=post.pk) # 작업이 끝나고 post_detail로 리다이렉트 else: form = PostForm() return render(request, 'blog/post_edit.html', {'form': form})

post_edit.html을 호출하게 되어있으므로 post_edit.html을 아래와 같이 생성한다.

from http://dbza.tistory.com/30 by ccl(A) rewrite - 2020-03-19 21:20:13

댓글

이 블로그의 인기 게시물

Django Rest Api 참고

Elasticsearch-dsl 삽질 복기(1)

django 설치 방법