C++ 如何使我的TCP侦听应用程序更安全?

C++ 如何使我的TCP侦听应用程序更安全?,c++,tcp,listen,honeypot,C++,Tcp,Listen,Honeypot,我正在寻找关于编写一个非常安全的C/C++应用程序的建议,该应用程序将侦听tcp端口。我想看看其他人正在试图对我的机器做什么,但如果我能用一个很短的程序完成我需要的事情,我不想安装一个精心制作的蜜罐应用程序。我的目标是简单和安全,我想确保我至少处理以下事项: 1) 客户端不能发送无限量的数据, 2) 客户端不应使用过多的连接和 3) 客户端不能无限期地保持连接打开。 因为我当前的应用程序很小而且功能齐全,所以第三方库似乎不适合这个项目。然而,一个能够进一步简化应用程序的小型库将是有趣的。此外,我

我正在寻找关于编写一个非常安全的C/C++应用程序的建议,该应用程序将侦听tcp端口。我想看看其他人正在试图对我的机器做什么,但如果我能用一个很短的程序完成我需要的事情,我不想安装一个精心制作的蜜罐应用程序。我的目标是简单和安全,我想确保我至少处理以下事项:
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个人)