2013/04/12

SQL Injection Prevention - Postgresql

這是一個 C 版本的 postgresql database 存取
#include <libpq-fe.h>

#define UPDATE_COMMAND   \
        "UPDATE employee SET password='%s' WHERE username='%s';"

int db_update(char *username, char *password)
{
  PGconn            *conn;
  PGresult          *res;
  ExecStatusType    status;
  char              query[1024];

  // connect to server

  /*
   * Set parameter
   */
  snprintf(query, sizeof(query), UPDATE_COMMAND, password, username);

  /*
   * Execute the query.
   */
  res = PQexec(conn, query);
  if (res) {
    status = PQresultStatus(res);
    if (status == PGRES_COMMAND_OK)) {
      printf("Update successfully\n");
    } else {
      printf("error message=[%s]\n", PQresultErrorMessage(res));
    }
  }
}
初學者容易犯的錯誤就是把 user input 直接跟 SQL query 串接在一起,如果 username, password 存在不安全的字眼,很有可能會造成 SQL injection,切記永遠不要相信 user 的資料,該做的檢查、防呆都不能少。


改成參數形式就可以避免 :)
Database client library 都會有提供類似的用法
#include <libpq-fe.h>

#define UPDATE_COMMAND   \
        "UPDATE employee SET password=$1 WHERE username=$2;"
#define PREPARED_STMT    "my_update"
#define NPARAMS          2

int db_update(char *username, char *password)
{
  PGconn            *conn;
  PGresult          *res;
  ExecStatusType    status;
  char              *params[NPARAMS];

  // connect to server

  /*
   * Set parameter
   */
  params[0] = password;
  params[1] = username;

  res = PQprepare(conn, PREPARED_STMT, UPDATE_COMMAND, NPARAMS, NULL);
  if (PQresultStatus(res) != PGRES_COMMAND_OK) {
    printf("PQprepare() failed [%s]", PQresultErrorMessage(res));
    return -1;
  }

  /*
   * Execute the query.
   */
  res = PQexecPrepared(conn, PREPARED_STMT, NPARAMS, 
                       (const char **)params, NULL, NULL, 0);
  if (res) {
    status = PQresultStatus(res);
    if (status == PGRES_COMMAND_OK)) {
      printf("Update successfully\n");
    } else {
      printf("error message=[%s]\n", PQresultErrorMessage(res));
    }
  }
}
關於 PQprepare()PQexecPrepared() 的使用方式可以參考官方文件


沒有留言:

張貼留言