|
| 1 | +<!-- |
| 2 | +{ |
| 3 | + "title": "XML Security with xmlFeatures", |
| 4 | + "id": "xml-security-xmlfeatures", |
| 5 | + "menuTitle": "XML Security (xmlFeatures)", |
| 6 | + "description": "How to control XML parsing security in Lucee using xmlFeatures to protect against XXE attacks and other XML vulnerabilities.", |
| 7 | + "keywords": [ |
| 8 | + "XML", |
| 9 | + "xmlFeatures", |
| 10 | + "XXE", |
| 11 | + "security", |
| 12 | + "xmlParse", |
| 13 | + "isXml", |
| 14 | + "external entities", |
| 15 | + "DOCTYPE" |
| 16 | + ], |
| 17 | + "categories": [ |
| 18 | + "xml", |
| 19 | + "security" |
| 20 | + ], |
| 21 | + "related": [ |
| 22 | + "function-xmlparse", |
| 23 | + "function-isxml", |
| 24 | + "function-xmlsearch" |
| 25 | + ] |
| 26 | +} |
| 27 | +--> |
| 28 | + |
| 29 | +# XML Security with xmlFeatures |
| 30 | + |
| 31 | +Since Lucee 5.4.2 and 6.0, XML parsing is **secure by default** to protect against [XML External Entity (XXE)](https://owasp.org/www-community/vulnerabilities/XML_External_Entity_(XXE)_Processing) attacks. DOCTYPE declarations and external entities are blocked out of the box. |
| 32 | + |
| 33 | +You can control XML security settings at two levels: |
| 34 | + |
| 35 | +- **Application-wide** via `this.xmlFeatures` in `Application.cfc` |
| 36 | +- **Per-call** by passing a struct as the `validator` argument to `xmlParse()`, or as the `xmlFeatures` argument to `isXml()` |
| 37 | + |
| 38 | +Per-call settings override the application-level settings for that single operation. |
| 39 | + |
| 40 | +## Built-in Feature Keys |
| 41 | + |
| 42 | +| Key | Type | Default | Description | |
| 43 | +|-----|------|---------|-------------| |
| 44 | +| `secure` | boolean | `true` | Master switch. When `true`, applies the full [OWASP XXE prevention](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html) settings: disallows DOCTYPE, disables external entities and parameter entities, disables external DTD loading, disables XInclude, and blocks access to external DTDs and schemas. | |
| 45 | +| `disallowDoctypeDecl` | boolean | `true` | When `true`, any XML containing a `<!DOCTYPE>` declaration throws an error. | |
| 46 | +| `externalGeneralEntities` | boolean | `false` | When `true`, allows the parser to resolve external entity references (e.g. `<!ENTITY xxe SYSTEM "file:///etc/passwd">`). | |
| 47 | +| `allowExternalEntities` | boolean | `false` | Adobe ColdFusion compatibility alias for `externalGeneralEntities`. If both are set, their values must match or an error is thrown. | |
| 48 | + |
| 49 | +The `secure` flag is applied first, then `disallowDoctypeDecl` and `externalGeneralEntities` override specific features on top. This means you can set `secure: true` but then selectively relax individual restrictions. |
| 50 | + |
| 51 | +## Setting xmlFeatures in Application.cfc |
| 52 | + |
| 53 | +The defaults are secure, so you only need to set `this.xmlFeatures` if you need to relax the restrictions: |
| 54 | + |
| 55 | +```luceescript |
| 56 | +// Application.cfc |
| 57 | +component { |
| 58 | + this.name = "myApp"; |
| 59 | +
|
| 60 | + // these are the defaults, you don't need to set them explicitly |
| 61 | + this.xmlFeatures = { |
| 62 | + "secure": true, |
| 63 | + "disallowDoctypeDecl": true, |
| 64 | + "externalGeneralEntities": false |
| 65 | + }; |
| 66 | +} |
| 67 | +``` |
| 68 | + |
| 69 | +To allow DOCTYPE declarations (e.g. for Hibernate mapping files or legacy XML with DTD references): |
| 70 | + |
| 71 | +```luceescript |
| 72 | +// Application.cfc |
| 73 | +component { |
| 74 | + this.name = "myApp"; |
| 75 | +
|
| 76 | + this.xmlFeatures = { |
| 77 | + "secure": false, |
| 78 | + "disallowDoctypeDecl": false, |
| 79 | + "externalGeneralEntities": false |
| 80 | + }; |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +You can also update the settings at runtime using `application action="update"`: |
| 85 | + |
| 86 | +```luceescript |
| 87 | +application action="update" xmlFeatures = { |
| 88 | + "secure": false, |
| 89 | + "disallowDoctypeDecl": false, |
| 90 | + "externalGeneralEntities": false |
| 91 | +}; |
| 92 | +``` |
| 93 | + |
| 94 | +## Per-call Override with xmlParse() |
| 95 | + |
| 96 | +You can override the application-level settings for a single `xmlParse()` call by passing a struct as the `validator` argument (the third argument): |
| 97 | + |
| 98 | +```luceescript |
| 99 | +// application has secure defaults, but this specific call allows DOCTYPE |
| 100 | +xml = xmlParse( xmlString, false, { |
| 101 | + "secure": false, |
| 102 | + "disallowDoctypeDecl": false, |
| 103 | + "externalGeneralEntities": false |
| 104 | +} ); |
| 105 | +``` |
| 106 | + |
| 107 | +This is useful when your application is secure by default but you need to parse a specific document that contains a DOCTYPE declaration. |
| 108 | + |
| 109 | +## Per-call Override with isXml() |
| 110 | + |
| 111 | +Similarly, `isXml()` accepts an `xmlFeatures` struct as its second argument: |
| 112 | + |
| 113 | +```luceescript |
| 114 | +// check if a string is valid XML, allowing DOCTYPE |
| 115 | +result = isXml( xmlString, { |
| 116 | + "secure": false, |
| 117 | + "disallowDoctypeDecl": false, |
| 118 | + "externalGeneralEntities": false |
| 119 | +} ); |
| 120 | +``` |
| 121 | + |
| 122 | +## Why the Defaults Block DOCTYPE |
| 123 | + |
| 124 | +By default, XML with a DOCTYPE declaration is rejected: |
| 125 | + |
| 126 | +```luceescript |
| 127 | +xmlString = '<?xml version="1.0"?> |
| 128 | + <!DOCTYPE foo [ |
| 129 | + <!ENTITY xxe SYSTEM "file:///etc/passwd"> |
| 130 | + ]> |
| 131 | + <foo>&xxe;</foo>'; |
| 132 | +
|
| 133 | +try { |
| 134 | + doc = xmlParse( xmlString ); |
| 135 | +} catch ( e ) { |
| 136 | + // "DOCTYPE is disallowed when the feature |
| 137 | + // http://apache.org/xml/features/disallow-doctype-decl set to true" |
| 138 | + echo( e.message ); |
| 139 | +} |
| 140 | +``` |
| 141 | + |
| 142 | +This is intentional. XXE attacks use DOCTYPE declarations to define external entities that can read local files, make network requests, or cause denial of service. Blocking DOCTYPE at the parser level is the most effective defense. |
| 143 | + |
| 144 | +## Pass-through Features |
| 145 | + |
| 146 | +Any keys in the struct that aren't one of the built-in aliases (`secure`, `disallowDoctypeDecl`, `externalGeneralEntities`, `allowExternalEntities`) are passed directly through to the underlying Java `DocumentBuilderFactory.setFeature()`. This lets you set any [Xerces feature](https://xerces.apache.org/xerces2-j/features.html): |
| 147 | + |
| 148 | +```luceescript |
| 149 | +this.xmlFeatures = { |
| 150 | + "secure": false, |
| 151 | + "disallowDoctypeDecl": false, |
| 152 | + "externalGeneralEntities": true, |
| 153 | + "http://apache.org/xml/features/validation/id-idref-checking": true |
| 154 | +}; |
| 155 | +``` |
| 156 | + |
| 157 | +You can also use the full Xerces URI form for the built-in features: |
| 158 | + |
| 159 | +```luceescript |
| 160 | +// equivalent to disallowDoctypeDecl: true |
| 161 | +application action="update" xmlFeatures = { |
| 162 | + "http://apache.org/xml/features/disallow-doctype-decl": true |
| 163 | +}; |
| 164 | +``` |
| 165 | + |
| 166 | +## System-level Lock-down |
| 167 | + |
| 168 | +The system property or environment variable `lucee.xmlfeatures.override.disable` can be set to `true` to prevent any application-level or per-call overrides. When enabled, XML parsing is locked to the secure defaults and any attempt to override will throw an error. |
| 169 | + |
| 170 | +This is useful for shared hosting environments where you want to enforce XML security across all applications. |
| 171 | + |
| 172 | +``` |
| 173 | +-Dlucee.xmlfeatures.override.disable=true |
| 174 | +``` |
| 175 | + |
| 176 | +Or as an environment variable: |
| 177 | + |
| 178 | +``` |
| 179 | +LUCEE_XMLFEATURES_OVERRIDE_DISABLE=true |
| 180 | +``` |
| 181 | + |
| 182 | +## What `secure: true` Does Under the Hood |
| 183 | + |
| 184 | +When `secure` is `true`, Lucee configures the Java XML parser following the [OWASP XXE Prevention Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/XML_External_Entity_Prevention_Cheat_Sheet.html): |
| 185 | + |
| 186 | +- `http://apache.org/xml/features/disallow-doctype-decl` = `true` |
| 187 | +- `http://xml.org/sax/features/external-general-entities` = `false` |
| 188 | +- `http://xml.org/sax/features/external-parameter-entities` = `false` |
| 189 | +- `http://apache.org/xml/features/nonvalidating/load-external-dtd` = `false` |
| 190 | +- XInclude aware = `false` |
| 191 | +- Expand entity references = `false` |
| 192 | +- Access to external DTD = blocked |
| 193 | +- Access to external schema = blocked |
| 194 | + |
| 195 | +The `disallowDoctypeDecl` and `externalGeneralEntities` settings are then applied on top, allowing you to selectively relax specific restrictions while keeping the rest of the secure configuration in place. |
0 commit comments