0
votes

The BSD/POSIX socket API recvfrom() call (made available to C or C++ programmers via the <sys/socket.h> header file) provides a source address "out" parameter, struct sockaddr *src_addr, which stores the IP address of the remote server that sent the received datagram.

For any application that sends UDP datagrams to some remote endpoint, and then receives a response (such as, for example, a DNS resolver), is it considered a necessary security precaution to always make sure that any received datagram is from the same IP address as the last sent datagram (i.e. the address used in the previous sendto call?)

In other words, if we call sendto and send a datagram to some address, should we always make sure that a corresponding recvfrom call is from the same address?

It seems that this might not be feasible, considering that a response datagram might legitimately originate from a different IP if the remote server is behind a firewall, or part of some distributed system with multiple IP addresses.

But, if we don't verify that a received datagram is from the same IP address as the address from the last sendto call, what's to prevent some attacker from intercepting datagrams, and then sending malicious datagrams to the client?

4

4 Answers

2
votes

How do you know that the received packet is a reply? Normally that's done using the source address and port from the received packet.

However, it is impossible to verify the source address in a UDP packet. A sender can place any source address they want to. So the check is only sufficient if you trust all the packets floating around on the internet, which is obviously not feasible.

So you need some additional mechanism: randomized cookies, sequence numbers, etc. etc.

2
votes

For any application that sends UDP datagrams to some remote endpoint, and then receives a response (such as, for example, a DNS resolver),

You could use a random outbound port number. This is how DNS can mitigate spoofing attacks.

is it considered a necessary security precaution to always make sure that any received datagram is from the same IP address as the last sent datagram (i.e. the address used in the previous sendto call?)

In other words, if we call sendto and send a datagram to some address, should we always make sure that a corresponding recvfrom call is from the same address?

Not just for security, but for functionality. If you have multiple outbound connections you need to know which UDP replies correspond to each connection. This can be achieved via IP address & port combination on the remote side.

It seems that this might not be feasible, considering that a response datagram might legitimately originate from a different IP if the remote server is behind a firewall, or part of some distributed system with multiple IP addresses.

A remote system should send the reply via the same interface that it received it on. If it doesn't, it will be "non standard' and won't work with your application, or others where it needs to receive and reply to UDP packets.

But, if we don't verify that a received datagram is from the same IP address as the address from the last sendto call, what's to prevent some attacker from intercepting datagrams, and then sending malicious datagrams to the client?

Nothing. If an attacker can MITM a UDP connection then they can intercept and change whatever they want. They could just send UDP packets with spoofed IP addresses to your service.

If you need to preserve integrity and confidentiality of packets, you need to implement some sort of encryption. For example. check out DTLS if you need to support datagrams.

0
votes

Some NAT supports UDP hole-punching that also do exactly the IP validation you mentioned, so it's not necessary to do it in application.

For custom protocol, You may want to implement some sort of sequence number in your payload, to further increase security level.

0
votes

In the general case it isn't true that an arbitrarily received datagram is a response to the previous request. You have to fllter, e.g. via connect(), to ensure that you only process responses that are responses.