You can use these best practices to create more efficient application filters.
When working with BSTR strings, the implementing entity should be responsible for allocating and freeing memory. For example, if the Firewall service allocates the memory, it should also free it.
A likely scenario is the case where an application filter needs to use a BSTR held by the Firewall service. The Firewall service should provide a pointer to the BSTR, so that the application filter can allocate memory, copy the BSTR, and be responsible for freeing the memory. This approach reduces the likelihood of memory leaks.
For example, there may be a race between calls to Detach (IFWXDataFilter::Detach or IFWXSessionFilter::Detach) and other methods. Data filters receive IFWXSocket interfaces when the IFWXDataFilter::SetSockets API is called. Because the Firewall service is multithreaded, more than one thread can use the same IFWXSocket interface simultaneously. Furthermore, one thread may call Detach to release an IFWXSocket interface, while the other thread still attempts to access the interface, perhaps while doing a data pump. Access to the interface should be protected by a locking mechanism, such as a critical section. Because of locking by the Firewall service, deadlock situations may arise. For example, the following code can lead to a deadlock situation:
Lock(); HRESULT hr = spSocket->Close(FALSE); Unlock();
To avoid the deadlock, use this code:
// Copy the member interface pointer to a local "smart" pointer // while the object is locked. CComPtr<IFWXSocket> spSocket; Lock(); spSocket = m_InternalSocket; Unlock(); // lock released to avoid deadlocks // Verify that interface was not released by Detach() if (spSocket != NULL) { // Here it is safe to send, receive, or close the socket. HRESULT hr = spSocket->Close(FALSE); }
There are situations where an application filter limits IP address access, including a:
For security purposes, the application filter defines a range of IP addresses for which a particular connection is allowed. Define that range of IP addresses by using the IFWXIpFilter interface.
Note If you set the range of IP addresses equal to NULL, you are allowing all addresses to connect.
When no data filter is present, the Firewall service user-mode data pump controls resource usage by limiting the number of pending sends on a connection in either direction. For a given communication direction, buffers are received as long as there are less than two pending sends. If there are two pending sends, the receive is delayed until a send is completed. This prevents the accumulation of data buffers when the send rate does not match the receive rate.
When an application filter that uses a data filter is added to the data pump, the send-limiting mechanism does not operate. Your application filter should therefore check whether each send is completed, and should establish a limit as to how many sends can accumulate. When the limit has been reached, your filter should stop calling receive until the number of sends drops below the limit. If you do not create this type of resource usage control mechanism, a large download or a deliberate attack could cause buffers to accumulate, using extensive non-paged pool and user-mode memory. This could result in a denial of service.
During inbound or output emulation, a filter may build up an excessive number of pending I/O operations and overflow the Firewall service. A filter should impose a strict limit on the number of pending I/O operations that it allows.
Application filters should be designed not to allocate excessive amounts of memory per session or request so that they will not become vulnerable to a denial-of-service (DoS) attack. If filters accumulate data (for example, until there is a complete message), they should set a maximum message size. If this maximum message size is significant, we also recommend that they limit the time during which a message can be stored.
Application filters should never trust data. They should verify that the data is coming from the correct side. For example, they should verify that the client is not sending information that should be coming only from the server. Your filter should also verify that the data has the correct format.
When using hash tables, use salt and other mechanisms to make sure that clients will not be able to craft data that will always be sent to the same bucket.
If an application filter also provides an extension for Forefront TMG Management, the setup program should allow for separate installation of the administration component and the filter component because Forefront TMG Management can be run remotely. In particular, Forefront TMG Management can be run from a remote computer on which the Forefront TMG services are not installed.
During filter registration, the error code HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS) should be considered as a success code, and installation should continue in a normal flow. This is done to avoid problems in re-registering an existing filter.
When an application filter is being uninstalled, the filter should try to uninstall all the objects that it registered (events, alerts, etc.), even if some of them no longer exist and an error code is returned. This is done to ensure that maximum cleanup is achieved, and to ensure forward compatibility with future support for array mode.
Application filters should not attempt to write to the stored Forefront TMG configuration. Application filters are allowed read-only access to the stored Forefront TMG configuration. Therefore, an application filter that relies on successfully writing to the stored configuration will fail.
Any changes to the stored configuration that are needed for an application filter should be made by the setup process or through the application filter's administrative component.
An attacker can use an event or an alert to consume the resources of Forefront TMG computers by sending network traffic of a certain type. To mitigate the risk of denial-of-service (DoS) attacks, application filters should avoid signaling an event using the IFPCEventDefinition::Signal method for each occurrence of a network event that may occur many times in a short period of time. An application filter should maintain a record of the last time that each event was signaled and limit the total number of events that can be signaled in a short period of time (for example, to two or three times a second).
Similarly, an application filter should include a mechanism for preventing each alert that is issued by it from being issued more than once per second.
Send comments about this topic to Microsoft
Build date: 11/30/2009
© 2008 Microsoft Corporation. All rights reserved.