Web应用防火墙开发

发布于 2024-10-08 13:24:35 字数 186 浏览 4 评论 0原文

我有一项任务是开发 Web 应用程序防火墙。我一直在研究一些相关的源代码。我的主要来源是 ModSecurity。

主要问题是:

- 我可以使用哪种框架或编程语言来开发 Web 应用程序防火墙?哪一个最有用?

-我可以使用 Django & Python?

这将是该项目研究的起点。

I have an assignment to develop a web application firewall. I have been researching for some source codes about that.My main source was ModSecurity.

Main question is that:

-Which framework or programming language I can use, to develop a web application firewall? Which one would be the most useful?

-Can I use Django & Python?

It would be a starting point for the project research.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

如果没有你 2024-10-15 13:24:36

好吧,所以我的猜测基本上是正确的,虽然我认为它是在保护一个没有安全性或安全性很差的应用程序,但它更多的是防止攻击。在这种情况下,Django 肯定是错误的。这在 Python 中显然是可行的,但不要指望能够每秒处理 100.000 个请求。 :) 但如果是研究和开发,我认为 Python 可能是一个不错的选择,因为它的开发速度很快,而且使用 Cython 这样的工具,它的运行速度也相当快。如果您最终制作的成品确实需要极高的性能,您可以采用算法并将其转换为 C/C++。

我会根据你的情况调查一下 Twisted。这可能是正确的解决方案。


“它将在服务器端用于通过 HTTP 控制用户事务。”

大多数 Web 应用程序框架都有安全设置。这些通常不被称为“防火墙”,并且您没有回答我的问题,所以我将在这里猜测:

您正在编写一个网络代理,它将过滤掉没有正确权限的请求,因为有根本没有任何访问控制的应用程序。这是正确的吗?

是的,您可以在 Python 中做到这一点。 Django 可能不是正确的解决方案。如果您需要通过登录页面和用户管理实现访问控制,那么您可能需要 SQL 和模板,轻量级 Python 框架可能会有所帮助。否则,Twisted 或仅使用标准库中的功能可能是正确的解决方案。

OK, so my guess was basically correct, although I thought it was protecting an app with no or bad security, but it's more about protecting against attacks. In that Case, Django is definitely wrong. It's clearly doable in Python, but don't expect to be able to handle 100.000 requests per second. :) But if it's research and development, I think Python can be a great choice, as it's fast to develop in, and with tools like Cython it can be quite fast to run as well. Should you then end up making a finished product that does need extreme performance, you can take the algorithms and translate them to C/C++.

I'd look into Twisted in your case. That may be the correct solution.


"It will be used on the server side to control the user transactions via HTTP."

Most web application frameworks have security settings. These are usually not called "firewalls", and you didn't answer my questions, so I'm going to guess here:

You are writing a web proxy that will act to filter out requests which do not have the correct permission because there is an application which does not have any access control at all. Is this correct?

Yes, you can do that in Python. Django is probably not the correct solution. If you need to implement access control with login pages and user management, then you probably want SQL and templating and a lightweight Python framework could be helpful. Otherwise Twisted or just doing it with the functionality in standard lib might be the correct solution.

养猫人 2024-10-15 13:24:36

这就是你需要做的,对于开始使用Linux,比Windows更容易处理,你有2个选择,第一个是通过挂钩系统调用来实现NetFilter驱动程序(更复杂!),第二个是使用libnetfilter_queue库和 iptables 将数据包传输到用户空间应用程序,主要思想是除了检查 IP 和 TCP 标头之外,还对有效负载进行深入分析,非常类似于 IDS、IPS 系统,但它专注于 Web 应用程序安全漏洞。

我认为你不能在没有更深层次干扰的情况下使用 python 做到这一点,你在这里问的问题非常棘手,它涉及系统的较低级别...

你可以使用这个示例开始分析数据:

将 iptables

#: iptables -A INPUT  -j NFQUEUE --queue-balance 0:3
#: iptables -A OUTPUT  -j NFQUEUE --queue-balance 4:8

队列 0 配置为3是针对所有输入(最好划分到不同的队列,队列可以容纳的数据包有限制),另一个是针对所有

用C编写应用程序的输出(iptables将数据包从内核传输到用户空间)

filterQueue.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <string.h>

/* for ethernet header */
#include<net/ethernet.h>

/* for UDP header */
#include<linux/udp.h>

/* for TCP header */
#include<linux/tcp.h>

/* for IP header */
#include<linux/ip.h>

/*  -20 (maximum priority) */
#include <sys/time.h>
#include <sys/resource.h>

/* for NF_ACCEPT */
#include <linux/netfilter.h>

/* for Threads */
#include <pthread.h>

/* for Queue */
#include <libnetfilter_queue/libnetfilter_queue.h>

#define NUM_THREADS     15

pthread_t threads[NUM_THREADS];

void printTCP(unsigned char *buffer) {

 unsigned short iphdrlen;

 struct iphdr *iph = (struct iphdr *) (buffer + sizeof(struct ethhdr));
 iphdrlen = iph->ihl * 4;

 struct tcphdr *tcph = (struct tcphdr *) (buffer + iphdrlen
   + sizeof(struct ethhdr));

 int header_size = sizeof(struct ethhdr) + iphdrlen + tcph->doff * 4;

 printf("| Packet Type: TCP \n");
 printf("|-Source Port      : %u\n", ntohs(tcph->source));
 printf("|-Destination Port : %u\n", ntohs(tcph->dest));
 printf("|-Sequence Number    : %u\n", ntohl(tcph->seq));
 printf("|-Acknowledge Number : %u\n", ntohl(tcph->ack_seq));
 printf("|-Header Length      : %d DWORDS or %d BYTES\n",
   (unsigned int) tcph->doff, (unsigned int) tcph->doff * 4);
 printf("|-CWR Flag : %d\n", (unsigned int) tcph->cwr);
 printf("|-ECN Flag : %d\n", (unsigned int) tcph->ece);
 printf("|-Urgent Flag          : %d\n", (unsigned int) tcph->urg);
 printf("|-Acknowledgement Flag : %d\n", (unsigned int) tcph->ack);
 printf("|-Push Flag            : %d\n", (unsigned int) tcph->psh);
 printf("|-Reset Flag           : %d\n", (unsigned int) tcph->rst);
 printf("|-Synchronise Flag     : %d\n", (unsigned int) tcph->syn);
 printf("|-Finish Flag          : %d\n", (unsigned int) tcph->fin);
 printf("|-Window         : %d\n", ntohs(tcph->window));
 printf("|-Checksum       : %d\n", ntohs(tcph->check));
 printf("|-Urgent Pointer : %d\n", tcph->urg_ptr);
}

void printUDP(unsigned char *buffer) {
 unsigned short iphdrlen;

 struct iphdr *iph = (struct iphdr *) (buffer + sizeof(struct ethhdr));
 iphdrlen = iph->ihl * 4;

 struct udphdr *udph = (struct udphdr*) (buffer + iphdrlen
   + sizeof(struct ethhdr));

 int header_size = sizeof(struct ethhdr) + iphdrlen + sizeof udph;

 printf("| Packet Type: UDP \n");
 printf("|-Source Port      : %u\n", ntohs(udph->source));
 printf("|-Destination Port : %u\n", ntohs(udph->dest));
 printf("|-UDP Length : %u\n", ntohs(udph->len));
 printf("|-UDP Checksum : %u\n", ntohs(udph->check));

}

char * getText(unsigned char * data, char Size) {

 char * text = malloc(Size);
 int i = 0;

 for (i = 0; i < Size; i++) {
  if (data[i] >= 32 && data[i] <= 128)
   text[i] = (unsigned char) data[i];
  else
   text[i] = '.';
 }
 return text;

}

u_int32_t analyzePacket(struct nfq_data *tb, int *blockFlag) {

 //packet id in the queue
 int id = 0;

 //the queue header
 struct nfqnl_msg_packet_hdr *ph;

 //the packet
 char *data;

 //packet size
 int ret;

 //extracting the queue header
 ph = nfq_get_msg_packet_hdr(tb);

 //getting the id of the packet in the queue
 if (ph)
  id = ntohl(ph->packet_id);

 //getting the length and the payload of the packet
 ret = nfq_get_payload(tb, &data);
 if (ret >= 0) {

  printf("Packet Received: %d \n", ret);

  /* extracting the ipheader from packet */
  struct sockaddr_in source, dest;
  unsigned short iphdrlen;

  struct iphdr *iph = ((struct iphdr *) data);
  iphdrlen = iph->ihl * 4;

  memset(&source, 0, sizeof(source));
  source.sin_addr.s_addr = iph->saddr;

  memset(&dest, 0, sizeof(dest));
  dest.sin_addr.s_addr = iph->daddr;

  printf("|-Source IP: %s\n", inet_ntoa(source.sin_addr));
  printf("|-Destination IP: %s\n", inet_ntoa(dest.sin_addr));
  printf("|-Checking for Protocol: \n");

  if (iph->protocol == 6) {
   printTCP(data);
  } else if (iph->protocol == 17) {
   printUDP(data);
  }

  printf("|-Extracting Payload: \n");

  char * text = getText(data, ret);

  //filtering requests for facebook
  if (text && text[0] != '\0') {
   printf("\n %s \n", text);
   ret = strstr(text, "facebook");
   if (ret == 0)
    //not found in string
    *blockFlag = 0;
   else
    //found in string
    *blockFlag = 1;
  }

  //release the packet
  free(text);


 }
 //return the queue id
 return id;

}

int packetHandler(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa,
  void *data) {

 printf("entering callback \n");

 //when to drop
 int blockFlag = 0;

 //analyze the packet and return the packet id in the queue
 u_int32_t id = analyzePacket(nfa, &blockFlag);

 //this is the point where we decide the destiny of the packet
 if (blockFlag == 0)
  return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
 else
  return nfq_set_verdict(qh, id, NF_DROP, 0, NULL);



}

void *QueueThread(void *threadid) {

 //thread id
 long tid;
 tid = (long) threadid;


 struct nfq_handle *h;
 struct nfq_q_handle *qh;
 char buf[128000] __attribute__ ((aligned));

 //pointers and descriptors
 int fd;
 int rv;
 int ql;


 printf("open handle to the netfilter_queue - > Thread: %d \n", tid);
 h = nfq_open();
 if (!h) {
  fprintf(stderr, "cannot open nfq_open()\n");
  return NULL;
 }

 //unbinding previous procfs
 if (nfq_unbind_pf(h, AF_INET) < 0) {
  fprintf(stderr, "error during nfq_unbind_pf()\n");
  return NULL;
 }

 //binding the netlink procfs
 if (nfq_bind_pf(h, AF_INET) < 0) {
  fprintf(stderr, "error during nfq_bind_pf()\n");
  return NULL;
 }

 //connet the thread for specific socket
 printf("binding this socket to queue '%d'\n", tid);
 qh = nfq_create_queue(h, tid, &packetHandler, NULL);
 if (!qh) {
  fprintf(stderr, "error during nfq_create_queue()\n");
  return NULL;
 }

 //set queue length before start dropping packages
 ql = nfq_set_queue_maxlen(qh, 100000);

 //set the queue for copy mode
 if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
  fprintf(stderr, "can't set packet_copy mode\n");
  return NULL;
 }

 //getting the file descriptor
 fd = nfq_fd(h);

 while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
  printf("pkt received in Thread: %d \n", tid);
  nfq_handle_packet(h, buf, rv);
 }

 printf("unbinding from queue Thread: %d  \n", tid);
 nfq_destroy_queue(qh);

 printf("closing library handle\n");
 nfq_close(h);

 return NULL;

}

int main(int argc, char *argv[]) {

 //set process priority
 setpriority(PRIO_PROCESS, 0, -20);

 int rc;
 long balancerSocket;
 for (balancerSocket = 0; balancerSocket < NUM_THREADS; balancerSocket++) {
  printf("In main: creating thread %ld\n", balancerSocket);

  //send the balancer socket for the queue
  rc = pthread_create(&threads[balancerSocket], NULL, QueueThread,
    (void *) balancerSocket);

  if (rc) {
   printf("ERROR; return code from pthread_create() is %d\n", rc);
   exit(-1);
  }
 }

 while (1) {
  sleep(10);
 }

 //destroy all threads
 pthread_exit(NULL);
}

this is what you need to do, for start use Linux, much easier to handle then Windows, you have 2 options, the first is to implement NetFilter driver by hooking to the system calls (More Complex!) , the second is to use libnetfilter_queue library and iptables to transfer the packet to a user space application, the main idea is to do deep analysis to the payload beside checking the IP and TCP header, very similar IDS,IPS systems but it's focusing on web application security holes.

i don't think you can do this with python without deeper interfering, what you asking here is pretty tricky, it's involved the lowers levels of the system...

you can start analyze the data using this example:

configure the iptables

#: iptables -A INPUT  -j NFQUEUE --queue-balance 0:3
#: iptables -A OUTPUT  -j NFQUEUE --queue-balance 4:8

queues 0 to 3 is for all inputs (better to divided to different queue, there is limit for packets the queue can hold),the other are for all outputs

writing application in C (the iptables transfer the packet from the kernel to user space)

filterQueue.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <string.h>

/* for ethernet header */
#include<net/ethernet.h>

/* for UDP header */
#include<linux/udp.h>

/* for TCP header */
#include<linux/tcp.h>

/* for IP header */
#include<linux/ip.h>

/*  -20 (maximum priority) */
#include <sys/time.h>
#include <sys/resource.h>

/* for NF_ACCEPT */
#include <linux/netfilter.h>

/* for Threads */
#include <pthread.h>

/* for Queue */
#include <libnetfilter_queue/libnetfilter_queue.h>

#define NUM_THREADS     15

pthread_t threads[NUM_THREADS];

void printTCP(unsigned char *buffer) {

 unsigned short iphdrlen;

 struct iphdr *iph = (struct iphdr *) (buffer + sizeof(struct ethhdr));
 iphdrlen = iph->ihl * 4;

 struct tcphdr *tcph = (struct tcphdr *) (buffer + iphdrlen
   + sizeof(struct ethhdr));

 int header_size = sizeof(struct ethhdr) + iphdrlen + tcph->doff * 4;

 printf("| Packet Type: TCP \n");
 printf("|-Source Port      : %u\n", ntohs(tcph->source));
 printf("|-Destination Port : %u\n", ntohs(tcph->dest));
 printf("|-Sequence Number    : %u\n", ntohl(tcph->seq));
 printf("|-Acknowledge Number : %u\n", ntohl(tcph->ack_seq));
 printf("|-Header Length      : %d DWORDS or %d BYTES\n",
   (unsigned int) tcph->doff, (unsigned int) tcph->doff * 4);
 printf("|-CWR Flag : %d\n", (unsigned int) tcph->cwr);
 printf("|-ECN Flag : %d\n", (unsigned int) tcph->ece);
 printf("|-Urgent Flag          : %d\n", (unsigned int) tcph->urg);
 printf("|-Acknowledgement Flag : %d\n", (unsigned int) tcph->ack);
 printf("|-Push Flag            : %d\n", (unsigned int) tcph->psh);
 printf("|-Reset Flag           : %d\n", (unsigned int) tcph->rst);
 printf("|-Synchronise Flag     : %d\n", (unsigned int) tcph->syn);
 printf("|-Finish Flag          : %d\n", (unsigned int) tcph->fin);
 printf("|-Window         : %d\n", ntohs(tcph->window));
 printf("|-Checksum       : %d\n", ntohs(tcph->check));
 printf("|-Urgent Pointer : %d\n", tcph->urg_ptr);
}

void printUDP(unsigned char *buffer) {
 unsigned short iphdrlen;

 struct iphdr *iph = (struct iphdr *) (buffer + sizeof(struct ethhdr));
 iphdrlen = iph->ihl * 4;

 struct udphdr *udph = (struct udphdr*) (buffer + iphdrlen
   + sizeof(struct ethhdr));

 int header_size = sizeof(struct ethhdr) + iphdrlen + sizeof udph;

 printf("| Packet Type: UDP \n");
 printf("|-Source Port      : %u\n", ntohs(udph->source));
 printf("|-Destination Port : %u\n", ntohs(udph->dest));
 printf("|-UDP Length : %u\n", ntohs(udph->len));
 printf("|-UDP Checksum : %u\n", ntohs(udph->check));

}

char * getText(unsigned char * data, char Size) {

 char * text = malloc(Size);
 int i = 0;

 for (i = 0; i < Size; i++) {
  if (data[i] >= 32 && data[i] <= 128)
   text[i] = (unsigned char) data[i];
  else
   text[i] = '.';
 }
 return text;

}

u_int32_t analyzePacket(struct nfq_data *tb, int *blockFlag) {

 //packet id in the queue
 int id = 0;

 //the queue header
 struct nfqnl_msg_packet_hdr *ph;

 //the packet
 char *data;

 //packet size
 int ret;

 //extracting the queue header
 ph = nfq_get_msg_packet_hdr(tb);

 //getting the id of the packet in the queue
 if (ph)
  id = ntohl(ph->packet_id);

 //getting the length and the payload of the packet
 ret = nfq_get_payload(tb, &data);
 if (ret >= 0) {

  printf("Packet Received: %d \n", ret);

  /* extracting the ipheader from packet */
  struct sockaddr_in source, dest;
  unsigned short iphdrlen;

  struct iphdr *iph = ((struct iphdr *) data);
  iphdrlen = iph->ihl * 4;

  memset(&source, 0, sizeof(source));
  source.sin_addr.s_addr = iph->saddr;

  memset(&dest, 0, sizeof(dest));
  dest.sin_addr.s_addr = iph->daddr;

  printf("|-Source IP: %s\n", inet_ntoa(source.sin_addr));
  printf("|-Destination IP: %s\n", inet_ntoa(dest.sin_addr));
  printf("|-Checking for Protocol: \n");

  if (iph->protocol == 6) {
   printTCP(data);
  } else if (iph->protocol == 17) {
   printUDP(data);
  }

  printf("|-Extracting Payload: \n");

  char * text = getText(data, ret);

  //filtering requests for facebook
  if (text && text[0] != '\0') {
   printf("\n %s \n", text);
   ret = strstr(text, "facebook");
   if (ret == 0)
    //not found in string
    *blockFlag = 0;
   else
    //found in string
    *blockFlag = 1;
  }

  //release the packet
  free(text);


 }
 //return the queue id
 return id;

}

int packetHandler(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg, struct nfq_data *nfa,
  void *data) {

 printf("entering callback \n");

 //when to drop
 int blockFlag = 0;

 //analyze the packet and return the packet id in the queue
 u_int32_t id = analyzePacket(nfa, &blockFlag);

 //this is the point where we decide the destiny of the packet
 if (blockFlag == 0)
  return nfq_set_verdict(qh, id, NF_ACCEPT, 0, NULL);
 else
  return nfq_set_verdict(qh, id, NF_DROP, 0, NULL);



}

void *QueueThread(void *threadid) {

 //thread id
 long tid;
 tid = (long) threadid;


 struct nfq_handle *h;
 struct nfq_q_handle *qh;
 char buf[128000] __attribute__ ((aligned));

 //pointers and descriptors
 int fd;
 int rv;
 int ql;


 printf("open handle to the netfilter_queue - > Thread: %d \n", tid);
 h = nfq_open();
 if (!h) {
  fprintf(stderr, "cannot open nfq_open()\n");
  return NULL;
 }

 //unbinding previous procfs
 if (nfq_unbind_pf(h, AF_INET) < 0) {
  fprintf(stderr, "error during nfq_unbind_pf()\n");
  return NULL;
 }

 //binding the netlink procfs
 if (nfq_bind_pf(h, AF_INET) < 0) {
  fprintf(stderr, "error during nfq_bind_pf()\n");
  return NULL;
 }

 //connet the thread for specific socket
 printf("binding this socket to queue '%d'\n", tid);
 qh = nfq_create_queue(h, tid, &packetHandler, NULL);
 if (!qh) {
  fprintf(stderr, "error during nfq_create_queue()\n");
  return NULL;
 }

 //set queue length before start dropping packages
 ql = nfq_set_queue_maxlen(qh, 100000);

 //set the queue for copy mode
 if (nfq_set_mode(qh, NFQNL_COPY_PACKET, 0xffff) < 0) {
  fprintf(stderr, "can't set packet_copy mode\n");
  return NULL;
 }

 //getting the file descriptor
 fd = nfq_fd(h);

 while ((rv = recv(fd, buf, sizeof(buf), 0)) && rv >= 0) {
  printf("pkt received in Thread: %d \n", tid);
  nfq_handle_packet(h, buf, rv);
 }

 printf("unbinding from queue Thread: %d  \n", tid);
 nfq_destroy_queue(qh);

 printf("closing library handle\n");
 nfq_close(h);

 return NULL;

}

int main(int argc, char *argv[]) {

 //set process priority
 setpriority(PRIO_PROCESS, 0, -20);

 int rc;
 long balancerSocket;
 for (balancerSocket = 0; balancerSocket < NUM_THREADS; balancerSocket++) {
  printf("In main: creating thread %ld\n", balancerSocket);

  //send the balancer socket for the queue
  rc = pthread_create(&threads[balancerSocket], NULL, QueueThread,
    (void *) balancerSocket);

  if (rc) {
   printf("ERROR; return code from pthread_create() is %d\n", rc);
   exit(-1);
  }
 }

 while (1) {
  sleep(10);
 }

 //destroy all threads
 pthread_exit(NULL);
}
久伴你 2024-10-15 13:24:36

除非这只是某种学术练习并且 Python 可以帮助您快速完成它,否则我不认为像 Python 这样的高级语言是防火墙的最佳选择(老实说,我什至不知道这是否可能)。如果您正在计划某种代理/过滤器应用程序,那可能没问题,但无论如何都不需要 Django。

Unless this is just some kind of academic exercise and Python helps you get it done fast, I don't think a high level language like Python is the best choice for a firewall (I don't even know if it's possible honestly). If you're planning some sort of proxy/filter application, that might be fine, but Django isn't needed either way.

芯好空 2024-10-15 13:24:36

Django 是一个 Web 应用程序框架。我没有看到有人使用它编写防火墙实现。

Django is a web application framework. I don't see anyone writing a firewall implementation using it.

染火枫林 2024-10-15 13:24:36

C、C++、Golang、Lua 都是开发 Web 应用程序防火墙或网关的可选语言,但 django 不适合它。
C、C++可以开发nginx插件或者后端WAF。
Golang可以配合WAF开发网关,例如Janusec应用网关。
Lua可以扩展nginx访问控制并作为WAF工作。

C, C++, Golang, Lua are all optional languages to develop a Web Application Firewall or Gateway, but django is not suitable for it.
C, C++ can develop nginx plugin or backend WAF.
Golang can develop gateway with WAF, such as Janusec Application Gateway.
Lua can extend nginx access control and work as a WAF.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文