Mysql UDF 작성

1) 공유 라이브러리 파일 작성

윈도우는 lib, linux/unix 계열은 so 파일을 만들어야 한다.

CMake 를 이용하는게 더 간편하기에 자주 사용하는 명령어에 대해서만 간략하게 정리한다.

# cmake 최소 요구 버전 - 이하일시 에러 발생 CMAKE_MINIMUM_REQUIRED (VERSION 3.5)  # CMAKE_PROJECT_NAME 설정 PROJECT(name)  # project 이름을 콘솔에 출력 MESSAGE(${CMAKE_PROJECT_NAME})  # 전처리기 매크로 추가 ADD_DEFINITIONS(-fPIC)  # 바이너리 생성 ADD_EXECUTABLE(app foo.c bar.c)  # 라이브러리 생성 ADD_LIBRARY(app SHARED foo.c bar.c )  # 각 소스 파일에서 #include 구문으로 포함시킨 헤더 파일을 찾을 디렉토리 추가 INCLUDE_DIRECTORIES(include /usr/local/include)  # 링크 과정에서 필요한 라이브러리 디렉토리 목록 추가 LINK_DIRECTORIES(lib /usr/local/lib)  # Target에 포함된 소스 파일에서 #include 구문에 포함된 헤더 파일 찾을 디렉토리 추가 TARGET_INCLUDE_DIRECTORIES(include /usr/local/include) 

더 다양한 명렁에 대한 정리는 다음 블로그를 참조하면 된다.

CMake 명령어 정리
CMake Tutorial

2) UDF 작성

위에서 CMAKE를 작성하는 법에 대해 알아보았다. 이제 공유 라이브러리를 만들기 위해 필요한 소스 파일을 작성해야 한다.

Mysql UDF 는 2가지 종류로 작성할 수 있다.

  • xxx_init() -> xxx() -> xxx_deinit()
  • xxx_init() -> xxx_clear() -> xxx_add() -> xxx() -> xxx_deinit()

xxx()는 본문 함수이고 UDF를 추가하기 위해서는 위의 형식을 지키며 함수를 추가해줘야 한다. 첫번째 형식이 가장 일반적인 경우이다.

두번째 형식은 Aggregate UDF라고 Group으로 xxx() 함수를 적용시킬 수 있는 경우이다.

ex) select sum(cost) from table group by dept;

Header 추가

먼저 각 인자들의 Type 을 위해 mysql 헤더를 추가한다.

#include <mysql.h> 

init, deinit

기본적으로 init, deinit 과정이 있으며 각각 다음과 같은 역할을 한다.

init

  • set default properties
  • validate arguments
  • allocate resources
  • signal an error

deinit

  • de-allocate any resources
my_bool xxx_init(UDF_INIT * initid, UDF_ARGS * args, char * message) 
void xxx_deinit(UDF_INIT * initid); 

본문 함수 작성

xxx() 는 본문함수이며 return 값에 따라 2가지 타입으로 선언할 수 있다.

// Integer Type long long xxx(UDF_INIT *initid, UDF_ARGS *args, my_bool *is_null, my_bool *error);  // Real type double xxx(UDF_INIT *initid, UDF_ARGS *args, my_bool *is_null, my_bool *error);  // String type, DECIMCAL type도 동일하게 작성 char * xxx(UDF_INIT *initid, UDF_ARGS * args, char * result, unsigned long length, my_bool *is_null, my_bool *error); 

string return value에 대해서만 더 자세하게 적도록 한다.

char * xxx(UDF_INIT *initid, UDF_ARGS * args, char * result, unsigned long length, my_bool *is_null, my_bool *error) {     // xxx(arg1, arg2) 입력 파라미터 값을 받을 수 있음.     char arg1 = args->args[0];      char arg2 = args->args[1];      // 로직 작성     char *value = fn();      // 지역변수를 return하게 되면 안된다. result에 담아서 보내야 한다.     strcpy(result, value);      return result; } 

다음 링크를 참고하면 Mysql에서는 xxx() 함수에 대해 result라는 버퍼를 제공하는데(최적화 이유) 255 크기로 제한이 되어 있다. -- 운영체제와 mysql 메모리 관리 방식은 따로 공부를 해봐야겠다.

mysql udf return values

만약 255 이상의 데이터를 보내고 싶다면 어떻게 해야 할까? UDF_INIT * initid 인자를 이용해야 한다.

UDF_INIT 구조체는 result에 대한 정보를 정의할 수가 있다.

mysql UDF_INIT Ref

만약 xxx_init()에서 mysql에서 제공하는 buffer(result) 를 이용하지 않고 새로 만들었다면 아래와 같이 사용가능하다.

xxx_init(..) {     char * arr = malloc(1024);     initid->ptr = arr;     initid->max_length = 1024; }  char * xxx(UDF_INIT *initid, UDF_ARGS * args, char * result, unsigned long length, my_bool *is_null, my_bool *error) {     char * buffer = initid->ptr;      return buffer; }  xxx_deinit(..) {     char * arr = initid->ptr;      if(arr) {         free(arr);     } } 

3) Mysql 에 UDF 추가

linux 를 기준으로 설명하면 /usr/local/mysql/lib/plugin 디렉토리가 존재한다.

생성한 so 파일을 해당 디렉토리에 넣어준다.

다음 명령을 통해 udf 를 추가할 수 있다.

create function func1 returns string soname 'lib_mysqludf.so'; create function func2 returns integer soname 'lib_mysqludf.so'; 

정리

CMake부터 시작하여 UDF를 작성하여 mysql에 추가해보는 시간을 가졌다. 실습을 해보면서 링크 및 컴파일에 대한 개념이 부족함을 알게 되었고, Mysql과 운영체제에서의 메모리 관리 방식에 대해서도 공부를 해봐야 겠다는 생각이 들었다.

Aggregate UDF 에 대해서는 다른 블로그를 참고하면서 직접 구현해보면 좋을 것 같다. clear를 기준으로 group이 나뉜다고 생각하면 쉽다.

Selenium_install

이 포스팅은 AWS EC2 ubuntu에 Python과 Selenium을 설치하여 연동하는데 도움을 줄 수 있는 글입니다.

Python Install

apt로 python을 설치한다.

sudo apt install python

만약 아래와 같은 에러가 뜬다면

sudo apt-get install python-pip
Reading package lists... Done
Building dependency tree
Reading state information... Done
E: Unable to locate package python-pip

python-pip 가 universe repositories에 있기 때문에 local repo에다가 추가해줘야 한다.

sudo apt-get install software-properties-common
sudo apt-add-repository universe
sudo apt-get update
sudo apt-get install python-pip

Selenium Instal On Ubuntu

  1. Chrome Driver 설치

  2. ./install.sh 실행

만약 아래와 같은 에러가 뜬다면

※ selenium.common.exceptions.WebDriverException:
Message: unknown error: cannot find Chrome binary
// Add Key
$ wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | sudo apt-key add -

// Set repo
$ echo 'deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main' | sudo tee /etc/apt/sources.list.d/google-chrome.list

// Install package
$ sudo apt-get update
$ sudo apt-get install google-chrome-stable

Chrome Headless 사용

GUI 가 지원이 안되는 ubuntu에서 chrome driver를 이용하면 에러가 나는 경우가 있다.

이 경우에는 아래와 같이 headless option을 설정해줘야 한다.

options = webdriver.ChromeOptions()
    options.add_argument('--disable-extensions')
    options.add_argument('--headless')
    options.add_argument('--disable-gpu')
    options.add_argument('--no-sandbox')
    return webdriver.Chrome(chrome_options=options)

'IT > BackEnd' 카테고리의 다른 글

Mysql UDF 작성  (0) 2019.03.20
SSL 인증서 발급 및 Nginx 적용. 그리고 체인 이슈 해결하기  (1) 2018.02.28
Atom Remote-FTP package 소개  (0) 2017.11.02
JWT  (0) 2017.09.27

SSL 발급받기

SSL 인증서를 구입하기 위해 저렴한 사이트들이 많다. 나는 GOGETSSL에서 인증서를 구입했다.

SSL 인증서 발급받기 위한 자세한 사항은 아래의 링크에서 참고 하기 바란다.

GOGETSSL에서 인증서 발급받기

요점을 정리하면, 인증서 등록시 CSR Generate 를 클릭하게 되면 CSR Code와 Server private key가 생성이 된다.

private key에 필요한 정보를(적용할 도메인 url) 입력한 다음 단계를 진행하다 보면 도메인 소유 인증을 진행한다. 각자 도메인을 구입한 사이트에서 E-mail, DNS, HTTP, HTTPS 기반의 인증방식을 제공하니 메뉴얼대로 진행하면 된다.

(주의해야할 점은 기존의 private key는 한번 잃어버리면 다시 재발급이 안된다. CSR/private Key pair을 다시 생성해야 한다.)

나는 DNS 인증방식으로 진행하였고 제공된 CNAME 코드로 DNS 서버의 CNAME Recorde를 등록하였다.

입력한 인증 정보를 통해 인증 진행후 인증서 파일을 다운로드를 받을 수 있다.

Nginx에 적용하기

/etc/nginx/site-available 폴더에서 server block 이 설정된 파일을 들어가보자.

기본으로 아래와 같이 되어 있다. 아래의 코드의 의미를 살펴 보면 80번 포트로(HTTP프로토콜의 기본 포트) example.com 도메인으로 요청이 들어오면 해당하는 location에 명시된 행위를 하겠다는 것을 의미한다.

server {
  listen 80;
  server_name example.com;

  location / {

  }
}

우리는 SSL을 적용해야 하기 때문에 HTTPS의 기본포트인 443 포트를 적용해야 한다.

server {
  listen 443;
}

그리고 SSL 인증서 발급시 생성된 key 파일과 crt 파일을 서버에 위치시키고 다음과 같이 작성한다.

server {
  listen 443;
  server_name example.com
  root html;

  ssl       on;
  ssl_certificate /etc/nginx/ssl/my_domain.crt;
  ssl_certificate_key /etc/nginx/ssl/my_domain.key;
  ssl_prefer_server_ciphers on;
  ssl_session_timeout 5m;

  location / {

  }
}

보안을 위해 nginx에 ssl폴더에 넣었지만 보안을 위해 루트 권한 설정을 한다.

$ sudo chown -R root:root /etc/nginx/ssl;

이제 https://example.com 으로 접속하게 되면 접속이 되는 것을 확인할 수 있다.

Chain Error Issue

일반 최신 웹 브라우저에서 접속하면 정상적으로 인증이 통과되어 접속이 된다. 하지만 구형 웹브라우저나 일부 모바일기기의 웹뷰에서는 접속이 안되는 경우가 있다. 이를 위해 먼저 체인 인증서에 대해 알아보자

체인 인증서란?

루트 인증서와 발급 받은 서버 인증서 사이에 존재하는 인증서이다. 즉 루트 인증서와 서버 인증서 사이를 중개, 연결해준다는 것이다. SSL 동작 방식에 의거하여 웹 브라우저에서 CA라는 Root Certificate 에서 통과된 인증서인지를 확인 후 접속을 허락해준다.

근데 이 체인 인증서라는게 SSL 초장기에는 루트 인증서에서 바로 서버 인증서를 발급하였지만, 최신에는 기술 환경 변화에 맞게 체인인증서 발급 체계를 가지고 있다.

따라서 최신 웹 브라우저의 경우에는 최신 루트 인증서 뿐만 아니라 체인 인증서까지 보유하고 있지만, 구형 웹 브라우저나 일부 모바일 기기에서는 접속이 안되는게 이러한 이유가 존재한다.

체인 이슈 해결

서버쪽에서 명시적으로 현재 서버인증자가 누구이며 어떤 발급 단계를 통하였는지 알려주면 되는 것이다.



위 사진에서 전체 zip 파일을 다운 받는다. 그러면 내부에 3가지의 파일이 존재할 것이다.

my_domain.crt, AddTrust_External_CA_Root.crt, COMODO_RSA_Certification_Authority.crt

nginx CA 인증서를 명시할 지시자 없으므로 다음과 같이 SSL 인증서와 CA 인증서를 하나의 파일로 만들어야 한다.

$ cat my_domain.crt AddTrust_External_CA_Root.crt COMODO_RSA_Certification_Authority.crt > ssl-bundle

그리고 가끔씩 순서를 잘 못 맞춰서 key와 crt파일이 매칭이 되지 않는 경우가 있는데 이 때는 sslshopper 에서 매칭 여부를 확인할 수 있다.

이제 SSL 인증서와 CA 인증서를 하나로 합친 파일을 nginx에 등록시키자.

server {
  listen 443;
  server_name example.com
  root html;

  ssl       on;
  ssl_certificate /etc/nginx/ssl/ssl-bundle.crt;
  ssl_certificate_key /etc/nginx/ssl/my_domain.key;
  ssl_prefer_server_ciphers on;
  ssl_session_timeout 5m;

  location / {

  }
}

자, 그러면 체인 문제가 해결되었는지 sslshopper에서 확인해보자.

그림처럼 오른쪽에 Server hostname을 입력하고 확인해 보 수 있다.

'IT > BackEnd' 카테고리의 다른 글

Mysql UDF 작성  (0) 2019.03.20
Crawling을 위한 Selenium, Chrome Driver 설치  (0) 2018.07.15
Atom Remote-FTP package 소개  (0) 2017.11.02
JWT  (0) 2017.09.27

Atom Remote-FTP 패키지를 이용해 서버와 파일 전송하기

서버에 작업하였던 파일들을 로컬 디렉토리로 옮기고 싶을 때가 있다. 로컬에서 서버로 ssh 접속하였지만 반대로 서버측에서 로컬 컴퓨터로 접속하여 파일을 보내고 싶을 때는 로컬 컴퓨터에서 ftp 혹은 관련 프로토콜을 서비스 할 수 있어야 한다.

그런데 atom의 Remote-FTP 패키지를 이용하면 FileZila 처럼 원하는 remote path를 지정하여 파일을 가져오거나 업로딩 할 수 있다.

  1. 패키지 설치 후 프로젝트를 연다.

  2. Package -> Remote-FTP -> Toggle 을 클릭한다.

  3. Package -> Remote-FTP -> Create (s)FTP config file을 클릭하여 config file을 프로젝트에 추가한다.(.ftpignore 파일이 생성된다.)

  4. 메뉴의 connect, disconnect를 이용하여 연결 후 upload, download를 통해 파일 업로딩 및 다운로드를 할 수 있다.

.ftpignore 파일은 아래와 같이 remote path와 host, user, pass의 정보를 입력하면 된다.

{
    "protocol": "sftp",
    "host": "xxx.xxx.xxx.xxx",
    "port": 22,
    "user": "userName",
    "pass": "password",
    "promptForPass": false,
    "remote": "/var/lib/tomcat7/webapps/ROOT/file",
    "local": "",
    "agent": "",
    "privatekey": "",
    "passphrase": "",
    "hosthash": "",
    "ignorehost": true,
    "connTimeout": 10000,
    "keepalive": 10000,
    "keyboardInteractive": false,
    "keyboardInteractiveForPass": false,
    "remoteCommand": "",
    "remoteShell": "",
    "watch": [],
    "watchTimeout": 500
}
 


'IT > BackEnd' 카테고리의 다른 글

Mysql UDF 작성  (0) 2019.03.20
Crawling을 위한 Selenium, Chrome Driver 설치  (0) 2018.07.15
SSL 인증서 발급 및 Nginx 적용. 그리고 체인 이슈 해결하기  (1) 2018.02.28
JWT  (0) 2017.09.27
1. Cliam 기반의 토큰
JWT는 Claim을 JSON형태로 표현(개행문자 등이 있으면 Header 파일에 넣기 어렵기 때문에 base64 인코딩을 하여 하나의 문자열로 변환)




1) 사용자 인증 후 토큰 생성
- 서버에서 별도로 저장 x, 사용자 정보나 권한을 토큰에 넣어서 저장

2) API 호출시 token과 함께 보낸다.


2. 변조 방지

토큰이 변조 되지 않는다고 증명 -> 무결성

이 무결성은 signature나 HMAC을 사용하여 보장한다.
(원본 메시지에서 해쉬값 추출 + 비밀키로 복호화 -> 생성된 문자열을 토큰의 뒤에 삽입)
이로써 비밀키를 모르면 HMAC을 얻을 수 없다.

궁금점) 왜 비밀키로 암호화를 하지 않고 복호화를 하는가? 해쉬값이 이미 암호화가 되어서 그런가?


3. 서명 생성 방식

메시지를 HMAC 을 이용하여 무결성 보장했지만 보안을 위해 서명 방식을 추가했다. 서명 알고리즘 정보를 JSON으로 표 후 BASE64 인코딩한 후 문자열을 claim 정보 앞에 붙인다.




참고사이트


http://bcho.tistory.com/999

+ Recent posts