Добавил:
ИВТ (советую зайти в "Несортированное")rnПИН МАГА Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
40
Добавлен:
05.11.2024
Размер:
326.05 Кб
Скачать
    1. Задание 2.

      1. Реализация функции для взаимодействия с базой данных

Реализуйте любой из SQL запросов, который вы выполняли в одной из предыдущих работ в виде функции на языке С, взаимодействующей с базой данных. Предусмотрите защиту от SQL инъекции любым из приведенных выше способов.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <libpq-fe.h>

/* Функция выхода из программы с сообщением об ошибке. */

void err_exit(PGconn *conn) {

PQfinish(conn);

exit(1);

}

/* Функция печати результата запроса на экран */

void print_query(PGresult *res) {

int rows = PQntuples(res);

int cols = PQnfields(res);

for (int i = 0; i < rows; i++) {

for (int j = 0; j < cols; j++) {

printf("%s ", PQgetvalue(res, i, j));

}

printf("\n");

}

}

/*

* Функция поиска самого младшего студента в указанной группе

*/

void find_youngest_student_in_group(PGconn *conn, const char* group_number) {

const char *param_values[1] = { group_number };

PGresult *res = PQexecParams(

conn,

"SELECT last_name, first_name, birthday "

"FROM students "

"WHERE students_group_number = $1 "

"ORDER BY birthday DESC "

"LIMIT 1;",

1, // Количество параметров

NULL, // Массив типов параметров (NULL для автоматического определения)

param_values, // Массив значений параметров

NULL, // Длины параметров (NULL для текстовых параметров)

NULL, // Формат параметров (NULL для текста)

0 // Формат результата (0 для текстового)

);

if (PQresultStatus(res) != PGRES_TUPLES_OK) {

fprintf(stderr, "No data retrieved\n");

PQclear(res);

err_exit(conn);

}

printf("Самый младший студент в группе %s:\n", group_number);

print_query(res);

PQclear(res);

}

int main() {

// Подключение к серверу базы данных

PGconn *conn = PQconnectdb("user=SAB password=123456 dbname=postgres");

// Проверка статуса подключения

if (PQstatus(conn) == CONNECTION_BAD) {

fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));

err_exit(conn);

}

// Вызов функции поиска самого младшего студента в группе "ИВТ-43"

find_youngest_student_in_group(conn, "ИВТ-43");

PQfinish(conn);

return 0;

}

  1. Защита от SQL-инъекций:

    • Используем PQexecParams, где значение параметра group_name передается как отдельный параметр $1. Это позволяет избежать SQL-инъекций, поскольку PostgreSQL автоматически экранирует переданное значение.

  2. Запрос для нахождения самого младшего студента:

    • В запросе ORDER BY birthday DESC LIMIT 1 сортирует записи по дате рождения в порядке убывания и возвращает только первую запись, которая соответствует самому младшему студенту.

  3. Функция print_query:

    • Выводит результат запроса с информацией о фамилии, имени и дате рождения студента, позволяя просмотреть результат без необходимости повторной разработки кода вывода.

  1. Этот код найдет и отобразит самого младшего студента в группе «ИВТ-43» на основе даты рождения.

      1. Предупреждение об инъекции

Добавьте функцию, срабатывающую в случае попытки внедрения SQL инъекции и выводящее значение, что текущему пользователю вынесено предупреждение.

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <libpq-fe.h>

/* Функция выхода из программы с сообщением об ошибке. */

void err_exit(PGconn *conn) {

PQfinish(conn);

exit(1);

}

/* Функция печати результата запроса на экран */

void print_query(PGresult *res) {

int rows = PQntuples(res);

int cols = PQnfields(res);

for (int i = 0; i < rows; i++) {

for (int j = 0; j < cols; j++) {

printf("%s ", PQgetvalue(res, i, j));

}

printf("\n");

}

}

/*

* Функция проверки на SQL-инъекцию.

* Если найдены подозрительные символы, возвращает 1, иначе — 0.

*/

int detect_sql_injection(const char* input) {

// Символы, часто используемые в SQL-инъекциях

const char* blacklist[] = {"'", ";", "--", "/*", "*/", "#", "\""};

int n = sizeof(blacklist) / sizeof(blacklist[0]);

for (int i = 0; i < n; i++) {

if (strstr(input, blacklist[i]) != NULL) {

return 1; // Обнаружена потенциальная инъекция

}

}

return 0;

}

/*

* Функция поиска самого младшего студента в указанной группе.

* Выводит предупреждение при попытке SQL-инъекции.

*/

void find_youngest_student_in_group(PGconn *conn, const char* group_number) {

// Проверка на SQL-инъекцию

if (detect_sql_injection(group_number)) {

printf("Предупреждение: Попытка SQL-инъекции обнаружена. Доступ для текущего пользователя ограничен.\n");

return;

}

const char *param_values[1] = { group_number };

PGresult *res = PQexecParams(

conn,

"SELECT last_name, first_name, birthday "

"FROM students "

"WHERE students_group_number = $1 "

"ORDER BY birthday DESC "

"LIMIT 1;",

1, // Количество параметров

NULL, // Массив типов параметров (NULL для автоматического определения)

param_values, // Массив значений параметров

NULL, // Длины параметров (NULL для текстовых параметров)

NULL, // Формат параметров (NULL для текста)

0 // Формат результата (0 для текстового)

);

if (PQresultStatus(res) != PGRES_TUPLES_OK) {

fprintf(stderr, "No data retrieved\n");

PQclear(res);

err_exit(conn);

}

printf("Самый младший студент в группе %s:\n", group_number);

print_query(res);

PQclear(res);

}

int main() {

// Подключение к серверу базы данных

PGconn *conn = PQconnectdb("user=SAB password=123456 dbname=postgres");

// Проверка статуса подключения

if (PQstatus(conn) == CONNECTION_BAD) {

fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));

err_exit(conn);

}

// Ввод названия группы пользователем

char group_number[256];

printf("Введите название группы (например, ИТД-43): ");

fgets(group_number, sizeof(group_number), stdin);

// Удаление символа новой строки, если он есть

size_t len = strlen(group_number);

if (len > 0 && group_number[len - 1] == '\n') {

group_number[len - 1] = '\0';

}

// Вызов функции поиска самого младшего студента в указанной группе

find_youngest_student_in_group(conn, group_number);

PQfinish(conn);

return 0;

}

  • Функция detect_sql_injection:

  • Принимает строку input и проверяет её на наличие символов и последовательностей, часто встречающихся в SQL-инъекциях.

  • Если находят такие символы, возвращает 1 (обнаружена инъекция), иначе — 0.

  • Функция find_youngest_student_in_group:

  • Проверяет, содержит ли ввод пользователя потенциально опасные символы.

  • Если detect_sql_injection возвращает 1, выводит сообщение предупреждения и завершает функцию без выполнения SQL-запроса.

      1. Использование представлений

Замените вызов SQL запроса из программного кода на вызов представления. Объясните преимущества и недостатки такого подхода.

В pgADMIN – cоздать виртуальную таблицу

CREATE OR REPLACE VIEW youngest_student_in_group AS

SELECT last_name, first_name, birthday, students_group_number

FROM students

ORDER BY students_group_number, birthday DESC;

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <libpq-fe.h>

/* Функция выхода из программы с сообщением об ошибке. */

void err_exit(PGconn *conn) {

PQfinish(conn);

exit(1);

}

/* Функция печати результата запроса на экран */

void print_query(PGresult *res) {

int rows = PQntuples(res);

int cols = PQnfields(res);

for (int i = 0; i < rows; i++) {

for (int j = 0; j < cols; j++) {

printf("%s ", PQgetvalue(res, i, j));

}

printf("\n");

}

}

/*

* Функция проверки на SQL-инъекцию.

* Если найдены подозрительные символы, возвращает 1, иначе — 0.

*/

int detect_sql_injection(const char* input) {

// Символы, часто используемые в SQL-инъекциях

const char* blacklist[] = {"'", ";", "--", "/*", "*/", "#", "\""};

int n = sizeof(blacklist) / sizeof(blacklist[0]);

for (int i = 0; i < n; i++) {

if (strstr(input, blacklist[i]) != NULL) {

return 1; // Обнаружена потенциальная инъекция

}

}

return 0;

}

/*

* Функция поиска самого младшего студента в указанной группе.

* Выводит предупреждение при попытке SQL-инъекции.

*/

void find_youngest_student_in_group(PGconn *conn, const char* group_number) {

if (detect_sql_injection(group_number)) {

printf("Предупреждение: Попытка SQL-инъекции обнаружена. Доступ для текущего пользователя ограничен.\n");

return;

}

const char *param_values[1] = { group_number };

PGresult *res = PQexecParams(

conn,

"SELECT last_name, first_name, birthday "

"FROM youngest_student_in_group "

"WHERE students_group_number = $1 "

"LIMIT 1;",

1, // Количество параметров

NULL, // Массив типов параметров (NULL для автоматического определения)

param_values, // Массив значений параметров

NULL, // Длины параметров (NULL для текстовых параметров)

NULL, // Формат параметров (NULL для текста)

0 // Формат результата (0 для текстового)

);

if (PQresultStatus(res) != PGRES_TUPLES_OK) {

fprintf(stderr, "No data retrieved\n");

PQclear(res);

err_exit(conn);

}

printf("Самый младший студент в группе %s:\n", group_number);

print_query(res);

PQclear(res);

}

int main() {

// Подключение к серверу базы данных

PGconn *conn = PQconnectdb("user=SAB password=123456 dbname=postgres");

// Проверка статуса подключения

if (PQstatus(conn) == CONNECTION_BAD) {

fprintf(stderr, "Connection to database failed: %s\n", PQerrorMessage(conn));

err_exit(conn);

}

// Ввод названия группы пользователем

char group_number[256];

printf("Введите название группы (например, ИТД-43): ");

fgets(group_number, sizeof(group_number), stdin);

// Удаление символа новой строки, если он есть

size_t len = strlen(group_number);

if (len > 0 && group_number[len - 1] == '\n') {

group_number[len - 1] = '\0';

}

// Вызов функции поиска самого младшего студента в указанной группе

find_youngest_student_in_group(conn, group_number);

PQfinish(conn);

return 0;

}

Преимущества:

  1. Повышенная читаемость и упрощение кода: В коде больше не нужно писать длинный SQL-запрос. Достаточно простого запроса к представлению.

  2. Переиспользование и модульность: Представление можно использовать в разных частях приложения или другими приложениями, что делает код более гибким.

  3. Безопасность и защита от SQL-инъекций: Представления помогают централизовать доступ к данным и могут ограничить доступ к подмножествам данных, снижая риск утечек.

  4. Оптимизация запросов: В некоторых СУБД представления кэшируются, что может ускорить выполнение запросов. PostgreSQL, например, может оптимизировать запросы, учитывая представления, хотя это зависит от сложности запроса.

Недостатки:

  1. Производительность: Если представление не является материализованным, каждый раз при его вызове выполняется запрос на обновление данных, что может замедлить выполнение, особенно если данные большого объема.

  2. Сложность обновления: Любое изменение в представлении может потребовать обновления кода, если в нем учитываются структура и поля представления.

  3. Ограниченная гибкость: Представления фиксируют логику запроса, и если она часто изменяется, придется пересоздавать представления.

Соседние файлы в папке 8 laba
  • #
    05.11.20244.09 Кб252.2
  • #
    05.11.20244.02 Кб232.3
  • #
    05.11.2024326.05 Кб408 лаба.docx
  • #
    05.11.202428.19 Кб26main
  • #
    05.11.202410.84 Кб24main.c
  • #
    05.11.2024157 б23Makefile
  • #
    05.11.20243.35 Кб25zad1.1
  • #
    05.11.20242.56 Кб24zad2.1