面试题答案
一键面试1. 缓冲区溢出
- 产生原因:在C语言中,数组访问不做越界检查。当向缓冲区写入的数据超出其预先分配的大小时,就会发生缓冲区溢出。例如,在使用
strcpy
函数时,如果目标缓冲区不足以容纳源字符串,就会导致数据溢出到相邻内存区域。 - 防范措施:
- 使用安全的字符串处理函数,如
strncpy
代替strcpy
,snprintf
代替printf
。strncpy
最多复制指定长度的字符,snprintf
会限制输出字符串的长度,避免缓冲区溢出。 - 对输入数据进行严格的长度检查,在向缓冲区写入数据前,确保数据长度不超过缓冲区大小。
- 使用安全的字符串处理函数,如
- 代码实现:
#include <stdio.h>
#include <string.h>
int main() {
char buffer[10];
char source[] = "Hello, World!";
// 使用strncpy替代strcpy
strncpy(buffer, source, sizeof(buffer) - 1);
buffer[sizeof(buffer) - 1] = '\0'; // 手动添加字符串结束符
printf("%s\n", buffer);
return 0;
}
2. SQL注入
- 产生原因:当Web服务器接收用户输入,并将其直接拼接到SQL语句中执行时,如果用户输入包含恶意SQL语句,就会导致SQL注入。例如,在登录验证中,将用户输入的用户名和密码直接拼接到
SELECT
语句中。 - 防范措施:
- 使用参数化查询(预编译语句)。数据库API提供了这种机制,将SQL语句和参数分开传递,数据库会对参数进行适当的转义和处理,防止恶意SQL注入。
- 对用户输入进行严格的过滤和验证,只允许合法字符和格式的输入。
- 代码实现:以MySQL C API为例
#include <mysql/mysql.h>
#include <stdio.h>
int main() {
MYSQL *conn;
MYSQL_STMT *stmt;
MYSQL_BIND bind[2];
const char *sql = "SELECT * FROM users WHERE username =? AND password =?";
char username[50] = "testuser";
char password[50] = "testpass";
conn = mysql_init(NULL);
if (!conn) {
fprintf(stderr, "mysql_init() failed\n");
return 1;
}
if (!mysql_real_connect(conn, "localhost", "root", "password", "testdb", 0, NULL, 0)) {
fprintf(stderr, "mysql_real_connect() failed\n");
mysql_close(conn);
return 1;
}
stmt = mysql_stmt_init(conn);
if (!stmt) {
fprintf(stderr, "mysql_stmt_init() failed\n");
mysql_close(conn);
return 1;
}
if (mysql_stmt_prepare(stmt, sql, strlen(sql))) {
fprintf(stderr, "mysql_stmt_prepare() failed\n");
mysql_stmt_close(stmt);
mysql_close(conn);
return 1;
}
memset(bind, 0, sizeof(bind));
bind[0].buffer_type = MYSQL_TYPE_STRING;
bind[0].buffer = username;
bind[0].is_null = 0;
bind[0].length = strlen(username);
bind[1].buffer_type = MYSQL_TYPE_STRING;
bind[1].buffer = password;
bind[1].is_null = 0;
bind[1].length = strlen(password);
if (mysql_stmt_bind_param(stmt, bind)) {
fprintf(stderr, "mysql_stmt_bind_param() failed\n");
mysql_stmt_close(stmt);
mysql_close(conn);
return 1;
}
if (mysql_stmt_execute(stmt)) {
fprintf(stderr, "mysql_stmt_execute() failed\n");
mysql_stmt_close(stmt);
mysql_close(conn);
return 1;
}
// 处理结果
mysql_stmt_close(stmt);
mysql_close(conn);
return 0;
}
3. 安全检测机制设计
- 实时监测方法:
- 基于日志分析:记录服务器接收的所有请求和相关操作日志,通过分析日志中的异常模式来检测潜在的安全威胁。例如,检测大量重复的错误请求,或者包含特定恶意字符串的请求。
- 内存监测:使用工具如
valgrind
来监测服务器进程的内存使用情况,及时发现缓冲区溢出等内存相关的安全问题。可以在服务器启动时开启valgrind
监测,并将结果实时反馈给管理员。 - 网络流量监测:监控服务器的网络流量,检测异常的流量模式,如大量的请求来自同一IP地址,或者请求的数据包大小异常等。可以使用
libpcap
库来捕获和分析网络数据包。
- 预警实现:
- 邮件预警:当检测到潜在的安全威胁时,通过发送邮件的方式通知管理员。在Linux系统中,可以使用
sendmail
命令结合C语言的system
函数来实现邮件发送功能。 - 日志记录与通知:将检测到的安全威胁详细记录到日志文件中,并通过系统通知(如
notify - send
)告知管理员,以便及时采取措施。
- 邮件预警:当检测到潜在的安全威胁时,通过发送邮件的方式通知管理员。在Linux系统中,可以使用
// 简单的邮件发送示例
#include <stdio.h>
#include <stdlib.h>
void send_email(const char *subject, const char *message) {
char command[256];
snprintf(command, sizeof(command), "echo '%s' | mail -s '%s' admin@example.com", message, subject);
system(command);
}
以上代码实现了一个简单的邮件发送函数,在检测到安全威胁时,可以调用该函数发送预警邮件。同时,结合日志记录和网络流量分析等手段,构建一个较为完善的安全检测机制。