WCF: Woah, Complex, Frequently Misconfigured
Some technologies fail because they cannot do enough, and some are technologies that fail because they can do absolutely everything, including several things no one should attempt before lunch. Windows Communication Foundation belongs firmly in the second category.
WCF arrived with grand ambitions. It would unify distributed systems on the Microsoft stack. HTTP, HTTPS, TCP, named pipes, message queues, SOAP contracts, service contracts, data contracts, certificates, Windows authentication, transport security, message security, custom bindings, behaviors, throttling, hosting in IIS, hosting in Windows services, and likely communion with the spirit world if properly configured. It was a serious framework built for serious enterprise needs.
It was also a magnificent way to accidentally create insecure systems while feeling highly professional. The central challenge with WCF has never been a lack of security features. If anything, it suffers from excessive generosity. There are so many ways to secure a service that many teams successfully assembled three contradictory methods at once and called it architecture. When a platform offers dozens of knobs, dials, switches, and XML attributes, misconfiguration stops being an edge case and becomes the default operating mode.
Many organizations in 2012 are still running WCF services built several years ago by teams who have since transferred, resigned, or ascended into management where no one can ask them follow-up questions. The service remains critical. The configuration remains mysterious. The documentation, if it exists, describes a previous civilization.
A common lifecycle looks like this. The service begins as an internal utility using plain HTTP because setup was faster and “it’s only on the intranet.” Then it gains new consumers. Then a partner needs access. Then someone adds HTTPS. Then an old client cannot handle the change, so a second endpoint remains. Then another department needs TCP for performance. Then certificates expire quietly one weekend. Then everyone discovers the original developer named the production binding tempBinding2.
This is how legacy happens quietly, then all at once. WCF security often confuses teams because the terminology sounds reassuring while concealing complexity. Transport security usually means protecting the channel itself, such as HTTPS. That is often exactly what teams need. Message security can protect the message contents end-to-end through intermediaries, which sounds elegant until operations inherits it. Credential types multiply choices further. Windows auth, usernames, certificates, issued tokens, mixed modes, custom validators. By the time everyone agrees on an approach, two developers have changed jobs.
Many teams selected advanced options not because they were necessary, but because they existed. This is a common enterprise instinct. If there are six security modes, surely the sophisticated company chooses the fifth one. Often the safer answer was the boring one. Use HTTPS. Authenticate sanely. Authorize explicitly. Monitor calls. Go home on time.
Instead, organizations frequently built internal services with broad trust assumptions. Because callers were on the network, methods performed sensitive actions with minimal checks. Because users authenticated through Windows, developers assumed all authenticated callers were equally entitled. Because contracts were internal, oversized data models leaked far more information than required. A method meant to return account status quietly returned the entire customer object, emotional history included.
Serialization also deserves suspicion. Frameworks that make it easy to move objects around encourage developers to move entire universes when a few fields would do. Every extra property exposed is another chance to leak information, create versioning pain, or explain to audit why payroll data was available in a customer support service response.
Then there is configuration sprawl. WCF’s great talent was allowing major security posture to hide in XML that nobody wanted to touch. Somewhere in many enterprises sits a config file containing expired certificates, disabled validation, forgotten endpoints, and comments reading “DO NOT CHANGE THIS OR BILLING BREAKS.” These comments are less documentation than hostage notes.
What should sensible teams do?
First, simplify aggressively. If secure point-to-point communication solves the problem, use it. Do not adopt elaborate message-layer designs because they looked impressive in a whitepaper.
Second, inventory every endpoint. Many companies know they have a service but not how many doors it currently has.
Third, separate authentication from authorization. Knowing who called is not the same as deciding what they may do.
Fourth, log meaningful actions. If a service can reset accounts, export records, or modify billing, those calls should leave evidence.
Fifth, retire compatibility debt. Old endpoints are liabilities wearing nostalgia as camouflage. IE will die.
Developers should ask uncomfortable questions. Why does this service have three bindings. Who still uses the anonymous endpoint. Why does this method return forty properties. If the certificate expires tonight, who learns first: monitoring or accounting.
WCF was not a mistake. It solved real distributed computing problems in a Microsoft-heavy era. But it also demonstrated an enduring truth of engineering. Complexity creates employment and incidents in nearly equal measure.
Power is exciting during design meetings. Simplicity is exciting during outages.