C++ 如何使我的TCP侦听应用程序更安全?
我正在寻找关于编写一个非常安全的C/C++应用程序的建议,该应用程序将侦听tcp端口。我想看看其他人正在试图对我的机器做什么,但如果我能用一个很短的程序完成我需要的事情,我不想安装一个精心制作的蜜罐应用程序。我的目标是简单和安全,我想确保我至少处理以下事项:C++ 如何使我的TCP侦听应用程序更安全?,c++,tcp,listen,honeypot,C++,Tcp,Listen,Honeypot,我正在寻找关于编写一个非常安全的C/C++应用程序的建议,该应用程序将侦听tcp端口。我想看看其他人正在试图对我的机器做什么,但如果我能用一个很短的程序完成我需要的事情,我不想安装一个精心制作的蜜罐应用程序。我的目标是简单和安全,我想确保我至少处理以下事项: 1) 客户端不能发送无限量的数据, 2) 客户端不应使用过多的连接和 3) 客户端不能无限期地保持连接打开。 因为我当前的应用程序很小而且功能齐全,所以第三方库似乎不适合这个项目。然而,一个能够进一步简化应用程序的小型库将是有趣的。此外,我
1) 客户端不能发送无限量的数据,
2) 客户端不应使用过多的连接和
3) 客户端不能无限期地保持连接打开。
因为我当前的应用程序很小而且功能齐全,所以第三方库似乎不适合这个项目。然而,一个能够进一步简化应用程序的小型库将是有趣的。此外,我希望C++标准库可以帮助简化我的代码。 下面是我最初尝试的一些关键功能。此代码在Windows、OSX和Linux上编译 如何使应用程序更安全或更简单
void SafeClose(SOCKET s)
{
if (s == INVALID_SOCKET)
return;
shutdown(s, SHUT_RDWR);
closesocket(s);
}
void ProcessConnection(SOCKET sock, sockaddr_in *sockAddr)
{
time_t time1;
char szTime[TIME_BUF_SIZE];
char readBuf[READ_BUF_SIZE];
time(&time1);
strftime(szTime, TIME_BUF_SIZE-1, "%Y/%m/%d %H:%M:%S", localtime(&time1));
printf("%s - %s\n", szTime, inet_ntoa(sockAddr->sin_addr));
usleep(1000000); // Wait 1 second for client to send something
int actualReadCount = recv(sock, readBuf, READ_BUF_SIZE-1, 0);
if (actualReadCount < 0 || actualReadCount >= READ_BUF_SIZE){
actualReadCount = 0;
strcpy(readBuf, "(Nothing)");
} else {
CleanString(readBuf, actualReadCount); // Replace non-printable characters
readBuf[actualReadCount] = 0;
}
printf("%s\n\n", readBuf);
SafeClose(sock);
}
int main(int argc, char* argv[])
{
int port = 80;
char cmd[CMD_BUF_SIZE] = {0};
sockaddr_in newSockAddr;
sockaddr_in localSockAddr;
if(argc < 2){
printf("Usage: safelisten PORT\n\n");
return error_code;
}
error_code++;
port = atoi(argv[1]);
BuildCleanAsciiMap(); // Used to replace non-printable characters
localSockAddr.sin_family = AF_INET;
localSockAddr.sin_addr.s_addr = INADDR_ANY;
localSockAddr.sin_port = htons(port);
sizeNewSockAddr = sizeof newSockAddr;
CHK( listenSocket = socket(AF_INET, SOCK_STREAM, 0));
CHK( setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)));
CHK( bind(listenSocket, (sockaddr*)&localSockAddr, sizeof localSockAddr));
CHK( listen(listenSocket, BACKLOG));
CHK( SetNonBlocking(listenSocket));
CHK( SetNonBlocking(0)); // Set STDIN to nonblocking for linux
printf ("Listening on port: %d\nEnter q to quit.\n\n", port);
while(strcmp(cmd, "q")) // While the user has not entered q ...
{
newSocket = accept(listenSocket, (sockaddr*)&newSockAddr, &sizeNewSockAddr);
ReadCmd(cmd, CMD_BUF_SIZE);
if(newSocket == INVALID_SOCKET) {
// accept() would have blocked, thus we wait and try again
usleep(10000);
continue;
}
// Set to nonblocking because we don't want the client to dictate how
// long we are connected.
CHK( SetNonBlocking(newSocket));
ProcessConnection(newSocket, &newSockAddr);
}
SafeClose(listenSocket);
return 0;
}
void SafeClose(插座s)
{
if(s==无效的_套接字)
返回;
关闭(s,关闭\RDWR);
插座;
}
无效进程连接(SOCKET sock,sockaddr_in*sockaddr)
{
时间1;
char szTime[时间大小];
char readBuf[READ_BUF_SIZE];
时间(&time1);
strftime(szTime,TIME_BUF_SIZE-1,“%Y/%m/%d%H:%m:%S”,localtime(&time1));
printf(“%s-%s\n”,szTime,inet_ntoa(sockAddr->sin_addr));
usleep(1000000);//等待1秒,让客户端发送内容
int actualReadCount=recv(sock,readBuf,READ_BUF_SIZE-1,0);
如果(实际读取计数<0 | |实际读取计数>=读取大小){
实际读取计数=0;
strcpy(readBuf,“(无)”);
}否则{
CleanString(readBuf,actualReadCount);//替换不可打印的字符
readBuf[actualReadCount]=0;
}
printf(“%s\n\n”,readBuf);
安全关闭(sock);
}
int main(int argc,char*argv[])
{
int端口=80;
char cmd[cmd_BUF_SIZE]={0};
newSockAddr中的sockaddr_;
本地sockaddr中的sockaddr_;
如果(argc<2){
printf(“用法:safelisten端口\n\n”);
返回错误代码;
}
错误代码++;
端口=atoi(argv[1]);
buildCleanSciMap();//用于替换不可打印的字符
localSockAddr.sin_family=AF_INET;
localSockAddr.sin\u addr.s\u addr=INADDR\u ANY;
localSockAddr.sinu port=htons(端口);
sizeNewSockAddr=newSockAddr的大小;
CHK(listenSocket=socket(AF_INET,SOCK_STREAM,0));
CHK(setsockopt(listenSocket,SOL_SOCKET,SO_REUSEADDR,(char*)&on,sizeof(on));
CHK(绑定(listenSocket,(sockaddr*)和localSockAddr,localSockAddr的大小));
CHK(监听(listenSocket,BACKLOG));
CHK(SetNonBlocking(listenSocket));
CHK(SetNonBlocking(0));//对于linux,将STDIN设置为nonblocking
printf(“侦听端口:%d\n输入q退出。\n\n”,端口);
while(strcmp(cmd,“q”)//当用户尚未输入q时。。。
{
newSocket=accept(listenSocket,(sockaddr*)&newSockAddr,&sizeNewSockAddr);
ReadCmd(cmd,cmd_BUF_SIZE);
如果(newSocket==无效的_套接字){
//accept()将被阻止,因此我们等待并重试
美国LEEP(10000);
继续;
}
//设置为nonblocking,因为我们不希望客户端指定如何执行
//只要我们有联系。
CHK(SetNonBlocking(newSocket));
进程连接(newSocket和newSockAddr);
}
安全关闭(listenSocket);
返回0;
}
2) 客户端不应使用太多的数据使服务器过载
许多联系
您最好的选择是让路由器限制一个IP地址的连接数量,因为当您的程序获得连接信息时,已经分配了系统资源
1) 客户端不能发送无限量的数据
最好的选择是有一些可以发送的合理的最大值,只需跟踪您已读取的内容,一旦达到最大值限制,请关闭连接
3) 客户端不能无限期地保持连接打开
为此,您只需创建一个线程来开始倒计时,因此当连接打开一段特定时间后,它可能会超时,您只需关闭连接即可
还有其他更复杂的解决方案,但我认为这将是一个很好的起点
如果您想对(2)做些什么,请在内存中保留一个hashmap,只需增加已建立的连接数,但您可能还希望跟踪时间。您希望数据结构非常快速,因此可以决定是否需要提前断开连接
例如,如果hashmap中有两个long,则可以输入第一个连接的时间(unixtime或ticks)并递增,如果在不到一分钟的时间内获得10个连接,则开始关闭多余的连接,直到一分钟过去。然后删除该元素,如果它有足够长的连接时间,您相信它没有攻击您
此外,请确保验证传递给您的所有参数,并为任何字符串设置合理的最大值。我能看到的唯一真正“慢”的是网络连接。我看不出这怎么能做得更快。是什么让你觉得它很慢?如果你想使用C++标准的LIB,那么C标签是不合适的。不要在进程连接中调用“USELIP”。调用“选择”以等待套接字上的数据。否则,如果数据立即可用,你只会浪费整整一秒钟。
我宁愿不依赖第三方库
——那么十有八九你会做错。不可能知道所有的事情,安全性也不容易实现(实际上是9个人)