Lecture 8 of Introduction to Computer science

Lecture 8

이번 강의에서는 MVC Model에 해당하는 Database에 대한 내용이었다.




전주에 이은 MVC 구성이며 Database에 대해 학습을 시작한다.


가상의 주식을 사고 파는 사이트인 CS50 Finance에서 로그인을 하고,


사고자 하는 주식과 갯수를 정해서 buy를 클릭하면 구매가 가능한 간단한 사이트이며 다시 재로그인을 하여도 구매 내역이 저장되어 있는 것을 확인할 수 있다. 이는 내부 데이터베이스를 사용했음을 암시한다.


어떤 탭으로 접근하던 항상 로그인을 할 필요없이 계속 로그인 상태를 유지할 수 있는 이유는 쿠키(cookie)가 사용자 정보를 저장하고 이를 유효화하기 때문이다. 재미있게 클럽에서 도장을 찍어주고 그 도장만 보여주면 얼마든지 재입장 가능한 상황에 비유하여 설명하였다.


어떤 사이트건 로그인을 할 때 위와 같이 request-response 과정을 거친다. 단순 사이트 접속과 다른 점은 cookie가 존재한다는 것이다. 이때 굉장히 큰 랜덤값을 부여하며 이를 통해 로그인 상태를 유지할 수 있도록 하며 이를 세션이라는 것으로 설명한다.


위의 예시와 같이 쇼핑몰의 예시를 보면 구매를 위해 장바구니에 담아두면 실수로 브라우저를 종료하더라도 다시 접속하면,




해당 정보는 저장이 되어 있는 것을 확인할 수 있다. 서버에서는 실제적으로 dict type으로 쿠키정보를 저장하고 비교하여 사용자가 맞는지를 판별한다.


application.py는 위의 사이트를 구성하는 코드이다. 위에서 설명한 것 처럼 session에 dict type으로 해당 정보에 접근하는 것을 알 수 있다. (session[item] = ~~ )


또한 데이터베이스는 csv와 같이 구현이 되는데 실생활측면에서는 spreadsheet인 것이고 서버측면에서는 데이터베이스라고 불리는 것이다. 데이터베이스에는 굉장히 다양한 프로그램이 있으며 대표적으로는 MySQL, SQLite, Microsoft Access 등이 있다. 열은 data type이나 종류에 대한 Field이며 행은 data라고 보면 된다.


간단한 데이터베이스를 스프레드시트를 통해 작성하는 모습이며 파일명을 University로 수정하고 밑의 sheet1을 student로 변경하면 해당 시트는 students에 대한 table이 된다.


Sheet2는 faculty로 명명하고 다른 정보들을 저장하기 위해 작성한다면 University 데이터베이스 내의 또 다른 table이 되는 것이다.


SQL(Structured Query Language)에는 위와 같은 데이터타입들이 있다. 특별히 SQLite에 대해 알아본다.


Integer에는 smallint(2 bytes), integer(4 bytes), bigint(8 bytes)가 있으며 정수에 대한 내용을 저장한다. 4 bytes로는 4 billon에 대한 내용이 저장가능하다는 한계가 있어 8 bytes의 bigint가 등장하게 되었다고 한다.


Real에는 real(4 bytes), double precision(8 bytes)이며 실수값을 표현한다.


Numeric이라는 타입이 등장하는데 눈여겨 볼 것은 date라는 날짜를 표현하는 데이터형태이다. 보통 yyyy-mm-dd의 형태로 저장이 된다고하며 time의 경우도 비슷한 형태이다.


Text에는 char, varchar의 형태가 있고 각각의 특징이 있다. 이들은 공통적으로 원하는 만큼의 글자의 숫자에 따라 할당할 수 있으나 char의 경우 공간을 많이 확보하고 덜 사용할 경우 낭비하지만, varchar의 경우에는 100의 공간을 확보하여도 5만 사용한다면 나머지 95를 낭비하지않고 최적화한다. 그렇다면 char 타입을 사용할 이유가 없을 것 같지만 이는 timestamp와 같이 같은 같은 공간을 할당하는 것이 더 보기좋고 효율적인 경우가 있기 때문이다. (시간이 지날 수록 해당 칸의 데이터공간이 점점 늘어나는 문제)


이번에는 위의 SQL 개념들에 대해 실습을 위해 SQLite3에 접근하는 모습이다.


CREATE TABLE 명령어로 registrants라는 테이블을 생성하며 포함할 정보들은 id, name, dorm이며 이에 대한 타입을 설정한다. 마찬가지로 아무 내용도 나타나지 않으면 정상적으로 생성되었다는 뜻이다.


다음으로는 해당 테이블에 정보들을 입력하는 모습이며,


입력된 내용을 불러내려면 SELECT * FROM - 명령어를 통해 테이블에 접근이 가능하다. 이 때 *는 everything을 의미하며 만약 한가지 혹은 특정열만 반환받고자 하면 column name을 입력하면 된다.


데이터가 변경되어 수정하려면 UPDATE를 통해 변경이 가능한 것도 알 수 있다. 추가적으로 누가 기숙사를 옮겼는지에 대해 변경할 때 이름을 통해 변경할 수도 있겠지만 이보다는 primary key가 적용된 id로 변경하는 것이 좀 더 효과적이다.


이번에는 CS50에서 제공하는 SQLite GUI를 통해 데이터베이스에 접근하는 모습이다. 훨씬 깔끔하며 다루기 쉬운 인터페이스를 지원한다.


다시 테이블을 초기화 하여 registrants테이블을 생성하고 해당 테이블의 필드값들을 추가하는 모습이며 이전에 코드상으로 작성할 때보다 훨씬 쉽게 조작하는 것을 볼 수 있다. 또한 필드를 설정할 때 해당 값의 특징에 따라 타입을 잘 결정하고 크기또한 고려해야 됨을 알려준다. (birthdate이전에 age로 지정했었는데 age는 매년 변경되므로 데이터베이스에 적절치 않음)


추가적인 필드를 넣을때도 손쉽게 조작이 가능하고 적용하면,


적용이 된 화면을 볼 수 있다.


만약 코드를 입력하여 결과를 추출하고 싶다면 SQL tap에서 코드를 입력하면,


해당하는 내용이 반환되는 것을 알 수 있다.


lecture.py에서는 파이썬코드를 통해 SQL를 조작하는 방법에 대해 보여주고 있다. SQL함수를 import하여 froshims.db에 직접 접근하고 이를 행마다 존재하는 이름들을 registered와 결합하여 출력하는 코드이다.


이번에는 위의 내용을 index.html을 통해 결과를 보여주는 코드를 application.py에 짜놓은 모습이다. 크게 다른것은 없으며 flask를 사용하였다.


index.html을 보면 이전의 html들과 마찬가지로 ul tag 내에 jinja format으로 li tag사이에 해당값들을 반환하는 코드이다.


flask run을 통해 서버를 실행시키고 사이트에 접속하면 위와 같이 제대로 실행되는 것을 확인 할 수 있다.


데이터베이스에 누가 있는지 확인하고자 검색하는 조건을 걸려면 이전에 구글에서 ?q= 와 같은 포맷을 사용한 것처럼 위에서도 q라는 변수를 통해 검색을 할 수 있도록 코드를 변경한다.


해당 사이트에 접속하여 제대로 실행되는지 확인하는데 그렇지 않음을 확인할 수 있다.


그 이유는 {q}로 전달이 되는 정보가 ''내에 쌓여서 char로 입력이 되어야 하기 때문이다.


이번엔 음악 앨범에 대한 샘플 데이터베이스이며 이를 활용해 몇가지 기능을 사용하고자 한다. 시작하기 전 한가지 팁을 알려주는데 이전의 기숙사 사례에서 같은 이름이 반복적으로 사용되면 이는 또다른 메모리낭비이기 때문에 기숙사마다 번호를 부여하여 이를 매칭시켜 사용하는 것이 더 효율적이라고 할 수 있다.


위에서 얘기한 것처럼 효율적으로 관리하기 위해 AlbumId와 ArtistId가 숫자로 부여된 것을 볼 수 있고 이를 관리하기 위한 또 다른 테이블이 있음을 유추할 수 있다.


따라서 Id에 따른 Artist를 검색해보면,


해당 테이블에 따라 Artist가 반환되는 것을 볼 수 있다.


그리고 두개의 테이블에 공통적으로 ArtistId 필드가 존재하므로 이를 통해 테이블을 합치는 것도 가능한데 위의 조건은 Artist테이블의 ArtistId와 Album테이블의 ArtistId가 값을 때 Artist테이블에 Album을 추가하는 내용이다.


그러면 위와 같이 조건에 부합하는 새로운 병합테이블이 나타난다.


이번에는 Album 테이블에 title에 Rock이라는 단어가 포함되어 있는지 확인하는 쿼리이며 특이하게 '%Rock%'과 같은 형태로 사용해야됨을 알 수 있다.


SQL에서도 위와 같은 다양한 함수를 지원함을 알려주며,


이번에는 race conditions(경합 조건)이라는 내용에 대해 소개한다. 일례로 회원가입 시 아이디를 결정할 때 유저 두명이 동시에 이전에 없었던 새롭고 똑같은 아이디를 입력할 때 나타나는 현상을 말해준다. 이에 대한 해결책으로 한번 접근 시 5분정도 데이터베이스에 대한 접근권한을 주고 그 동안 다른 유저가 접근하지 못하도록 막는 방안을 얘기해준다.


또한 유저가 입력하는 내용을 믿으면 안된다는 말을 하며 유효하진 않지만 만약 위와 같은 내용을 삽입한다면 데이터베이스가 사라질 위험도 생길 수 있음을 상기시킨다.


따라서 이와 같은 악의적인 공격을 막기 위해 semicolon(:)을 사용함을 보여준다. 위에서는 {q}와 같이 직접적으로 입력을 받는 것 대신 유효한 필드에 대해 :name , name=q 와 같이 한번 거쳐서 입력을 받는 상태로 변경한 것을 볼 수 있다.


패스워드에 표기된 ' OR '1' = '1의 내용을 추정컨데,


이런 내용에 연계가 되었을 가능성을 보여준다. (실제와는 다름)


이는 위에서 표기된 내용을 입력 시 위와 같이 적용이 되어 어떤 랜덤한 유저로 접근이 되도록하는 코드라고 한다.


따라서 위와 같은 오용을 막고자 :기호를 사용함을 알 수 있었다.


이제까지 말한 악용한 사례를 실제적으로 사용한 사례라고 할 수 있는 사진이며 주차위반딱지를 떼는 것을 피하기 위해 데이터베이스를 삭제하는 코드를 붙인 것을 볼 수 있다. (지극정성..)


마지막으로는 위의 내용을 기반으로 한 개그 웹툰을 보여주면서 강의를 마쳤다.

댓글