or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

dom.mdelementtree.mdexceptions.mdindex.mdsax.mdstdlib-patching.mdxmlrpc.md

xmlrpc.mddocs/

0

# XML-RPC Protection

1

2

Secure XML-RPC client and server protection with gzip bomb prevention. DefusedXML provides defused parsers and decompression limits for XML-RPC communications, protecting against both XML-based attacks and gzip compression bombs that can cause denial of service through excessive memory consumption.

3

4

## Capabilities

5

6

### Monkey Patching Functions

7

8

Functions to apply and remove system-wide XML-RPC security patches.

9

10

```python { .api }

11

def monkey_patch():

12

"""

13

Apply security patches to XML-RPC modules system-wide.

14

15

Replaces xmlrpc.client.FastParser with DefusedExpatParser,

16

xmlrpc.client.GzipDecodedResponse with DefusedGzipDecodedResponse,

17

and xmlrpc.client.gzip_decode with defused_gzip_decode.

18

19

Also patches xmlrpc.server.gzip_decode if available (Python 3).

20

21

This is a global monkey patch that affects all XML-RPC usage

22

in the current Python process.

23

"""

24

25

def unmonkey_patch():

26

"""

27

Remove security patches from XML-RPC modules.

28

29

Restores original XML-RPC implementations by reverting

30

monkey patches applied by monkey_patch().

31

32

Warning: This removes security protections and should only

33

be used if defused XML-RPC processing is causing compatibility issues.

34

"""

35

```

36

37

**Usage Examples:**

38

39

```python

40

import defusedxml.xmlrpc as xmlrpc_defused

41

42

# Apply system-wide XML-RPC security patches

43

xmlrpc_defused.monkey_patch()

44

45

# Now all XML-RPC operations use secure implementations

46

import xmlrpc.client

47

server = xmlrpc.client.ServerProxy('http://example.com/xmlrpc')

48

result = server.some_method() # Uses defused parser

49

50

# Remove patches if needed (not recommended)

51

xmlrpc_defused.unmonkey_patch()

52

```

53

54

### Secure Gzip Decompression

55

56

Secure gzip decompression with configurable size limits to prevent gzip bomb attacks.

57

58

```python { .api }

59

def defused_gzip_decode(data, limit=None):

60

"""

61

Decompress gzip-encoded data with size limits to prevent gzip bombs.

62

63

Args:

64

data (bytes): Gzip-compressed data to decompress

65

limit (int, optional): Maximum decompressed size in bytes (default: MAX_DATA)

66

67

Returns:

68

bytes: Decompressed data

69

70

Raises:

71

ValueError: If decompressed data exceeds size limit or data is invalid

72

NotImplementedError: If gzip module is not available

73

"""

74

```

75

76

**Usage Examples:**

77

78

```python

79

import defusedxml.xmlrpc as xmlrpc_defused

80

81

# Decompress with default limit (30MB)

82

compressed_data = get_gzip_data()

83

try:

84

decompressed = xmlrpc_defused.defused_gzip_decode(compressed_data)

85

print(f"Decompressed {len(compressed_data)} bytes to {len(decompressed)} bytes")

86

except ValueError as e:

87

print(f"Gzip decompression failed: {e}")

88

89

# Decompress with custom limit (10MB)

90

try:

91

decompressed = xmlrpc_defused.defused_gzip_decode(compressed_data, limit=10*1024*1024)

92

except ValueError as e:

93

print(f"Data exceeded 10MB limit: {e}")

94

95

# Disable limit (not recommended for untrusted data)

96

decompressed = xmlrpc_defused.defused_gzip_decode(trusted_data, limit=-1)

97

```

98

99

### Secure XML-RPC Parser

100

101

Secure XML-RPC parser with configurable security restrictions for processing XML-RPC requests and responses.

102

103

```python { .api }

104

class DefusedExpatParser:

105

"""

106

Secure XML-RPC parser using expat with configurable security restrictions.

107

108

Replaces the standard XML-RPC FastParser with security handlers

109

to prevent XML bomb attacks, DTD processing attacks, and external

110

entity attacks in XML-RPC communications.

111

"""

112

113

def __init__(self, target, forbid_dtd=False, forbid_entities=True, forbid_external=True):

114

"""

115

Initialize DefusedExpatParser for XML-RPC processing.

116

117

Args:

118

target: XML-RPC target handler for processing parsed data

119

forbid_dtd (bool): Forbid DTD processing (default: False)

120

forbid_entities (bool): Forbid entity expansion (default: True)

121

forbid_external (bool): Forbid external references (default: True)

122

"""

123

124

def defused_start_doctype_decl(self, name, sysid, pubid, has_internal_subset):

125

"""Handler that raises DTDForbidden when DTD processing is forbidden"""

126

127

def defused_entity_decl(self, name, is_parameter_entity, value, base, sysid, pubid, notation_name):

128

"""Handler that raises EntitiesForbidden when entity processing is forbidden"""

129

130

def defused_unparsed_entity_decl(self, name, base, sysid, pubid, notation_name):

131

"""Handler that raises EntitiesForbidden for unparsed entities when forbidden"""

132

133

def defused_external_entity_ref_handler(self, context, base, sysid, pubid):

134

"""Handler that raises ExternalReferenceForbidden when external references are forbidden"""

135

```

136

137

### Secure Gzip Response Handler

138

139

Secure gzip response handler with size limits for processing compressed XML-RPC responses.

140

141

```python { .api }

142

class DefusedGzipDecodedResponse:

143

"""

144

Secure gzip-decoded response handler with size limits.

145

146

Replaces the standard GzipDecodedResponse with size limits

147

to prevent gzip bomb attacks that can consume excessive memory

148

through maliciously crafted compressed responses.

149

"""

150

151

def __init__(self, response, limit=None):

152

"""

153

Initialize DefusedGzipDecodedResponse with size limits.

154

155

Args:

156

response: HTTP response object containing gzip-compressed data

157

limit (int, optional): Maximum decompressed size in bytes (default: MAX_DATA)

158

159

Raises:

160

ValueError: If response data exceeds size limit

161

NotImplementedError: If gzip module is not available

162

"""

163

164

def read(self, n):

165

"""

166

Read and decompress up to n bytes from response.

167

168

Args:

169

n (int): Maximum number of bytes to read

170

171

Returns:

172

bytes: Decompressed data

173

174

Raises:

175

ValueError: If total decompressed data exceeds size limit

176

"""

177

178

def close(self):

179

"""Close the response and cleanup resources"""

180

```

181

182

### Configuration Constants

183

184

```python { .api }

185

MAX_DATA = 30 * 1024 * 1024 # Maximum data size limit (30MB)

186

```

187

188

**Usage Example:**

189

190

```python

191

import defusedxml.xmlrpc as xmlrpc_defused

192

193

# Custom size limit

194

custom_limit = 5 * 1024 * 1024 # 5MB

195

response_handler = xmlrpc_defused.DefusedGzipDecodedResponse(http_response, limit=custom_limit)

196

197

try:

198

data = response_handler.read(1024)

199

while data:

200

process_data(data)

201

data = response_handler.read(1024)

202

finally:

203

response_handler.close()

204

```

205

206

## Common Usage Patterns

207

208

### System-wide XML-RPC Protection

209

210

```python

211

import defusedxml.xmlrpc as xmlrpc_defused

212

213

# Apply protection at application startup

214

xmlrpc_defused.monkey_patch()

215

216

# Now all XML-RPC usage is automatically protected

217

import xmlrpc.client

218

219

def make_xmlrpc_call(server_url, method_name, *args):

220

"""Make XML-RPC call with automatic security protection."""

221

try:

222

server = xmlrpc.client.ServerProxy(server_url)

223

result = getattr(server, method_name)(*args)

224

return result

225

except xmlrpc.client.Fault as e:

226

print(f"XML-RPC fault: {e}")

227

except Exception as e:

228

print(f"XML-RPC error: {e}")

229

return None

230

231

# Make calls normally - they're automatically secured

232

result = make_xmlrpc_call('http://example.com/rpc', 'get_data', 'param1')

233

```

234

235

### Manual Parser Configuration

236

237

```python

238

import defusedxml.xmlrpc as xmlrpc_defused

239

import xmlrpc.client

240

241

class SecureXMLRPCTransport(xmlrpc.client.Transport):

242

"""Custom XML-RPC transport with defused parser."""

243

244

def getparser(self):

245

"""Return defused parser instead of standard parser."""

246

target = xmlrpc.client.Unmarshaller()

247

parser = xmlrpc_defused.DefusedExpatParser(

248

target,

249

forbid_dtd=True,

250

forbid_entities=True,

251

forbid_external=True

252

)

253

return parser, target

254

255

# Use custom transport

256

transport = SecureXMLRPCTransport()

257

server = xmlrpc.client.ServerProxy('http://example.com/rpc', transport=transport)

258

result = server.method_name()

259

```

260

261

### Gzip Decompression with Error Handling

262

263

```python

264

import defusedxml.xmlrpc as xmlrpc_defused

265

266

def safe_gzip_decode(compressed_data, max_size=None):

267

"""Safely decompress gzip data with error handling."""

268

try:

269

limit = max_size or xmlrpc_defused.MAX_DATA

270

decompressed = xmlrpc_defused.defused_gzip_decode(compressed_data, limit=limit)

271

272

print(f"Successfully decompressed {len(compressed_data)} bytes to {len(decompressed)} bytes")

273

return decompressed

274

275

except ValueError as e:

276

if "max gzipped payload length exceeded" in str(e):

277

print(f"Gzip bomb detected: compressed data would exceed {limit} bytes")

278

elif "invalid data" in str(e):

279

print("Invalid gzip data format")

280

else:

281

print(f"Gzip decompression error: {e}")

282

return None

283

except NotImplementedError:

284

print("Gzip module not available")

285

return None

286

```

287

288

### XML-RPC Server Protection

289

290

```python

291

import defusedxml.xmlrpc as xmlrpc_defused

292

from xmlrpc.server import SimpleXMLRPCServer

293

294

# Apply patches before creating server

295

xmlrpc_defused.monkey_patch()

296

297

class SecureXMLRPCServer(SimpleXMLRPCServer):

298

"""XML-RPC server with defused XML processing."""

299

300

def __init__(self, *args, **kwargs):

301

super().__init__(*args, **kwargs)

302

# Server automatically uses defused parsers due to monkey patching

303

304

def _dispatch(self, method, params):

305

"""Dispatch method calls with additional security logging."""

306

print(f"XML-RPC call: {method} with {len(params)} parameters")

307

return super()._dispatch(method, params)

308

309

# Create and run secure server

310

server = SecureXMLRPCServer(('localhost', 8000))

311

server.register_function(lambda x: x * 2, 'double')

312

313

print("Starting secure XML-RPC server...")

314

server.serve_forever()

315

```

316

317

### Conditional Security Configuration

318

319

```python

320

import defusedxml.xmlrpc as xmlrpc_defused

321

import os

322

323

def configure_xmlrpc_security():

324

"""Configure XML-RPC security based on environment."""

325

326

# Check if we're in a development environment

327

if os.getenv('ENVIRONMENT') == 'development':

328

print("Development mode: XML-RPC security monitoring only")

329

# Could implement logging-only mode here

330

else:

331

print("Production mode: Applying XML-RPC security patches")

332

xmlrpc_defused.monkey_patch()

333

334

def safe_xmlrpc_call(url, method, *args, max_response_size=None):

335

"""Make XML-RPC call with optional response size limits."""

336

import xmlrpc.client

337

338

# Set custom gzip limit if specified

339

if max_response_size:

340

original_max = xmlrpc_defused.MAX_DATA

341

xmlrpc_defused.MAX_DATA = max_response_size

342

343

try:

344

server = xmlrpc.client.ServerProxy(url)

345

result = getattr(server, method)(*args)

346

return result

347

finally:

348

# Restore original limit

349

if max_response_size:

350

xmlrpc_defused.MAX_DATA = original_max

351

352

# Configure security at startup

353

configure_xmlrpc_security()

354

355

# Make calls with custom limits

356

result = safe_xmlrpc_call('http://api.example.com/rpc', 'get_large_dataset', max_response_size=50*1024*1024)

357

```

358

359

## Migration from Standard Library

360

361

DefusedXML XML-RPC protection is typically applied via monkey patching:

362

363

```python

364

# Before (vulnerable)

365

import xmlrpc.client

366

server = xmlrpc.client.ServerProxy('http://example.com/rpc')

367

result = server.method()

368

369

# After (secure)

370

import defusedxml.xmlrpc as xmlrpc_defused

371

xmlrpc_defused.monkey_patch() # Apply protection system-wide

372

373

import xmlrpc.client

374

server = xmlrpc.client.ServerProxy('http://example.com/rpc')

375

result = server.method() # Now automatically protected

376

```

377

378

The monkey patching approach ensures all XML-RPC usage in the application is automatically secured without requiring code changes.