rack-libinjection 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.github/workflows/ci.yml +55 -0
- data/CHANGELOG.md +112 -0
- data/GET_STARTED.md +418 -0
- data/LICENSE-libinjection.txt +33 -0
- data/LICENSE.txt +21 -0
- data/README.md +68 -0
- data/SECURITY.md +65 -0
- data/ext/libinjection/extconf.rb +113 -0
- data/ext/libinjection/libinjection_ext.c +1132 -0
- data/ext/libinjection/vendor/libinjection/.vendored +5 -0
- data/ext/libinjection/vendor/libinjection/COPYING +33 -0
- data/ext/libinjection/vendor/libinjection/MIGRATION.md +393 -0
- data/ext/libinjection/vendor/libinjection/README.md +251 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection.h +70 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_error.h +26 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_html5.c +830 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_html5.h +56 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_sqli.c +2342 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_sqli.h +297 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_sqli_data.h +9651 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_xss.c +1203 -0
- data/ext/libinjection/vendor/libinjection/src/libinjection_xss.h +23 -0
- data/lib/libinjection/version.rb +6 -0
- data/lib/libinjection.rb +31 -0
- data/lib/rack/libinjection.rb +586 -0
- data/lib/rack-libinjection.rb +3 -0
- data/samples/README.md +67 -0
- data/samples/libinjection_detect_raw_hot_path.rb +161 -0
- data/samples/rack_all_surfaces_hot_path.rb +198 -0
- data/samples/rack_params_hot_path.rb +166 -0
- data/samples/rack_query_hot_path.rb +176 -0
- data/samples/results/.gitkeep +0 -0
- data/script/fuzz_smoke.rb +39 -0
- data/script/vendor_libs.rb +227 -0
- data/test/test_helper.rb +7 -0
- data/test/test_libinjection.rb +223 -0
- data/test/test_middleware.rb +404 -0
- metadata +148 -0
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
# rack-libinjection vendor manifest. Do not edit by hand. Regenerate with: ruby script/vendor_libs.rb
|
|
2
|
+
libinjection_version=4.0.0
|
|
3
|
+
libinjection_url=https://codeload.github.com/libinjection/libinjection/tar.gz/v4.0.0?dummy=/
|
|
4
|
+
libinjection_archive_sha256=a69d27e3d98608df89203c4e1c00c034fe0f8c723017e4088ab53ce3ff5a9129
|
|
5
|
+
libinjection_tree_sha256=de73d6fdaa9b51970142c74941031a058491d5c883bb1eca9faa8bf9f874703b
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
Copyright (c) 2012-2016, Nick Galbreath
|
|
2
|
+
Copyright (c) 2017-2024, libinjection Contributors
|
|
3
|
+
All rights reserved.
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are
|
|
7
|
+
met:
|
|
8
|
+
|
|
9
|
+
1. Redistributions of source code must retain the above copyright
|
|
10
|
+
notice, this list of conditions and the following disclaimer.
|
|
11
|
+
|
|
12
|
+
2. Redistributions in binary form must reproduce the above copyright
|
|
13
|
+
notice, this list of conditions and the following disclaimer in the
|
|
14
|
+
documentation and/or other materials provided with the distribution.
|
|
15
|
+
|
|
16
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
17
|
+
contributors may be used to endorse or promote products derived from
|
|
18
|
+
this software without specific prior written permission.
|
|
19
|
+
|
|
20
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
21
|
+
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
22
|
+
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
23
|
+
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
24
|
+
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
25
|
+
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
26
|
+
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
27
|
+
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
28
|
+
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
29
|
+
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
30
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
31
|
+
|
|
32
|
+
https://github.com/libinjection/libinjection
|
|
33
|
+
http://opensource.org/licenses/BSD-3-Clause
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
# Migration Guide: libinjection v3.x to v4.0
|
|
2
|
+
|
|
3
|
+
This guide helps you migrate from libinjection v3.x to v4.0, which introduces a breaking API change in error handling.
|
|
4
|
+
|
|
5
|
+
## Overview of Changes
|
|
6
|
+
|
|
7
|
+
Version 4.0 introduces a new error handling model that **prevents process termination** on parser errors. Instead of calling `abort()` when encountering invalid parser states, the library now returns an error code that your application can handle gracefully.
|
|
8
|
+
|
|
9
|
+
## What Changed
|
|
10
|
+
|
|
11
|
+
### Return Type Change
|
|
12
|
+
|
|
13
|
+
All detection functions now return `injection_result_t` enum instead of `int`:
|
|
14
|
+
|
|
15
|
+
```c
|
|
16
|
+
typedef enum injection_result_t {
|
|
17
|
+
LIBINJECTION_RESULT_FALSE = 0, // No injection detected (benign input)
|
|
18
|
+
LIBINJECTION_RESULT_TRUE = 1, // Injection detected
|
|
19
|
+
LIBINJECTION_RESULT_ERROR = -1 // Parser error (invalid state)
|
|
20
|
+
} injection_result_t;
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Affected Functions
|
|
24
|
+
|
|
25
|
+
- `libinjection_xss()`
|
|
26
|
+
- `libinjection_sqli()`
|
|
27
|
+
- `libinjection_is_xss()`
|
|
28
|
+
- `libinjection_h5_next()`
|
|
29
|
+
|
|
30
|
+
### New Header File
|
|
31
|
+
|
|
32
|
+
Include the new error header:
|
|
33
|
+
```c
|
|
34
|
+
#include "libinjection_error.h" // New in v4.0
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Migration Strategies
|
|
38
|
+
|
|
39
|
+
### Strategy 1: Full Migration (Recommended)
|
|
40
|
+
|
|
41
|
+
Update your code to explicitly check all three return values:
|
|
42
|
+
|
|
43
|
+
**Before (v3.x):**
|
|
44
|
+
```c
|
|
45
|
+
#include "libinjection.h"
|
|
46
|
+
#include "libinjection_sqli.h"
|
|
47
|
+
|
|
48
|
+
int check_input(const char *input) {
|
|
49
|
+
struct libinjection_sqli_state state;
|
|
50
|
+
char fingerprint[8];
|
|
51
|
+
int result;
|
|
52
|
+
|
|
53
|
+
libinjection_sqli_init(&state, input, strlen(input), FLAG_NONE);
|
|
54
|
+
result = libinjection_is_sqli(&state);
|
|
55
|
+
|
|
56
|
+
if (result) {
|
|
57
|
+
log("SQLi detected: %s", state.fingerprint);
|
|
58
|
+
return 1; // Block request
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return 0; // Allow request
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**After (v4.0):**
|
|
66
|
+
```c
|
|
67
|
+
#include "libinjection.h"
|
|
68
|
+
#include "libinjection_error.h"
|
|
69
|
+
#include "libinjection_sqli.h"
|
|
70
|
+
|
|
71
|
+
int check_input(const char *input) {
|
|
72
|
+
struct libinjection_sqli_state state;
|
|
73
|
+
char fingerprint[8];
|
|
74
|
+
injection_result_t result;
|
|
75
|
+
|
|
76
|
+
libinjection_sqli_init(&state, input, strlen(input), FLAG_NONE);
|
|
77
|
+
result = libinjection_is_sqli(&state);
|
|
78
|
+
|
|
79
|
+
if (result == LIBINJECTION_RESULT_ERROR) {
|
|
80
|
+
log_error("Parser error - treating as suspicious");
|
|
81
|
+
return 1; // Block on error (fail-safe)
|
|
82
|
+
} else if (result == LIBINJECTION_RESULT_TRUE) {
|
|
83
|
+
log("SQLi detected: %s", state.fingerprint);
|
|
84
|
+
return 1; // Block request
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return 0; // Allow request
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Strategy 2: Minimal Migration (Quick Fix)
|
|
92
|
+
|
|
93
|
+
For quick migration with minimal code changes, treat errors as detections:
|
|
94
|
+
|
|
95
|
+
```c
|
|
96
|
+
injection_result_t result;
|
|
97
|
+
|
|
98
|
+
result = libinjection_sqli(input, len, fingerprint);
|
|
99
|
+
|
|
100
|
+
// Treat error as detection (fail-safe approach)
|
|
101
|
+
if (result == LIBINJECTION_RESULT_TRUE || result == LIBINJECTION_RESULT_ERROR) {
|
|
102
|
+
// Block request
|
|
103
|
+
return 1;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return 0; // Allow only if LIBINJECTION_RESULT_FALSE
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Strategy 3: Backward Compatible Check
|
|
110
|
+
|
|
111
|
+
If you need to maintain compatibility during transition:
|
|
112
|
+
|
|
113
|
+
```c
|
|
114
|
+
injection_result_t result;
|
|
115
|
+
|
|
116
|
+
result = libinjection_xss(input, len);
|
|
117
|
+
|
|
118
|
+
// Old style: simple truthy check still works for detection
|
|
119
|
+
// but won't distinguish error from injection
|
|
120
|
+
if (result) {
|
|
121
|
+
// Handles both LIBINJECTION_RESULT_TRUE and LIBINJECTION_RESULT_ERROR (since -1 is truthy)
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return 0;
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
**Warning:** This approach treats errors as benign input when checking `!result`, which is unsafe.
|
|
129
|
+
|
|
130
|
+
## Migration by Use Case
|
|
131
|
+
|
|
132
|
+
### Web Application Firewall (WAF)
|
|
133
|
+
|
|
134
|
+
Recommended approach: **Fail-safe** - block on both detection and error.
|
|
135
|
+
|
|
136
|
+
```c
|
|
137
|
+
injection_result_t sqli_result = libinjection_sqli(input, len, fp);
|
|
138
|
+
injection_result_t xss_result = libinjection_xss(input, len);
|
|
139
|
+
|
|
140
|
+
if (sqli_result == LIBINJECTION_RESULT_TRUE || sqli_result == LIBINJECTION_RESULT_ERROR ||
|
|
141
|
+
xss_result == LIBINJECTION_RESULT_TRUE || xss_result == LIBINJECTION_RESULT_ERROR) {
|
|
142
|
+
|
|
143
|
+
log_security_event(input, sqli_result, xss_result);
|
|
144
|
+
return HTTP_403_FORBIDDEN;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return HTTP_200_OK;
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Logging/Monitoring System
|
|
151
|
+
|
|
152
|
+
Recommended approach: **Distinguish** between detection and errors.
|
|
153
|
+
|
|
154
|
+
```c
|
|
155
|
+
injection_result_t result = libinjection_xss(input, len);
|
|
156
|
+
|
|
157
|
+
switch (result) {
|
|
158
|
+
case LIBINJECTION_RESULT_TRUE:
|
|
159
|
+
log_metric("xss.detected", 1);
|
|
160
|
+
alert_security_team(input);
|
|
161
|
+
break;
|
|
162
|
+
|
|
163
|
+
case LIBINJECTION_RESULT_ERROR:
|
|
164
|
+
log_metric("xss.parser_error", 1);
|
|
165
|
+
log_error("Parser error on input: %.*s", (int)len, input);
|
|
166
|
+
// Continue processing - may be benign malformed input
|
|
167
|
+
break;
|
|
168
|
+
|
|
169
|
+
case LIBINJECTION_RESULT_FALSE:
|
|
170
|
+
log_metric("xss.clean", 1);
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Embedded System
|
|
176
|
+
|
|
177
|
+
Recommended approach: **Graceful degradation** with error recovery.
|
|
178
|
+
|
|
179
|
+
```c
|
|
180
|
+
injection_result_t result = libinjection_sqli(input, len, fp);
|
|
181
|
+
|
|
182
|
+
if (result == LIBINJECTION_RESULT_ERROR) {
|
|
183
|
+
// Log error but don't block - keep system running
|
|
184
|
+
error_count++;
|
|
185
|
+
|
|
186
|
+
if (error_count > ERROR_THRESHOLD) {
|
|
187
|
+
// Too many errors - may indicate attack or bug
|
|
188
|
+
enter_safe_mode();
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return ALLOW; // Degrade gracefully
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return (result == LIBINJECTION_RESULT_TRUE) ? BLOCK : ALLOW;
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Testing Your Migration
|
|
198
|
+
|
|
199
|
+
### 1. Compile-time Checks
|
|
200
|
+
|
|
201
|
+
After migration, your code should compile with the new type:
|
|
202
|
+
|
|
203
|
+
```c
|
|
204
|
+
injection_result_t result; // Not 'int'
|
|
205
|
+
result = libinjection_xss(input, len);
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
### 2. Runtime Testing
|
|
209
|
+
|
|
210
|
+
Test with these scenarios:
|
|
211
|
+
|
|
212
|
+
```c
|
|
213
|
+
// Normal detection - should return LIBINJECTION_RESULT_TRUE
|
|
214
|
+
libinjection_xss("<script>alert(1)</script>", 28);
|
|
215
|
+
|
|
216
|
+
// Benign input - should return LIBINJECTION_RESULT_FALSE
|
|
217
|
+
libinjection_xss("hello world", 11);
|
|
218
|
+
|
|
219
|
+
// Edge cases that might trigger LIBINJECTION_RESULT_ERROR
|
|
220
|
+
libinjection_xss("", 0); // Empty string
|
|
221
|
+
// Very long inputs, deeply nested structures, etc.
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### 3. Error Handling Test
|
|
225
|
+
|
|
226
|
+
Verify your error handling:
|
|
227
|
+
|
|
228
|
+
```c
|
|
229
|
+
injection_result_t result = libinjection_xss(test_input, len);
|
|
230
|
+
|
|
231
|
+
assert(result == LIBINJECTION_RESULT_FALSE ||
|
|
232
|
+
result == LIBINJECTION_RESULT_TRUE ||
|
|
233
|
+
result == LIBINJECTION_RESULT_ERROR); // Only valid values
|
|
234
|
+
|
|
235
|
+
// Ensure you handle all three cases
|
|
236
|
+
switch (result) {
|
|
237
|
+
case LIBINJECTION_RESULT_FALSE: /* ... */ break;
|
|
238
|
+
case LIBINJECTION_RESULT_TRUE: /* ... */ break;
|
|
239
|
+
case LIBINJECTION_RESULT_ERROR: /* ... */ break;
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Common Pitfalls
|
|
244
|
+
|
|
245
|
+
### ❌ Don't: Ignore errors
|
|
246
|
+
|
|
247
|
+
```c
|
|
248
|
+
// WRONG - error becomes benign
|
|
249
|
+
if (result == LIBINJECTION_RESULT_TRUE) {
|
|
250
|
+
block();
|
|
251
|
+
}
|
|
252
|
+
// LIBINJECTION_RESULT_ERROR falls through as allowed!
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### ✅ Do: Explicitly handle errors
|
|
256
|
+
|
|
257
|
+
```c
|
|
258
|
+
// CORRECT
|
|
259
|
+
if (result == LIBINJECTION_RESULT_ERROR) {
|
|
260
|
+
handle_error();
|
|
261
|
+
} else if (result == LIBINJECTION_RESULT_TRUE) {
|
|
262
|
+
block();
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### ❌ Don't: Use simple equality for "not detected"
|
|
267
|
+
|
|
268
|
+
```c
|
|
269
|
+
// WRONG - error will pass this check
|
|
270
|
+
if (result == 0) { // Only catches LIBINJECTION_RESULT_FALSE
|
|
271
|
+
allow();
|
|
272
|
+
}
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### ✅ Do: Use enum constants
|
|
276
|
+
|
|
277
|
+
```c
|
|
278
|
+
// CORRECT
|
|
279
|
+
if (result == LIBINJECTION_RESULT_FALSE) {
|
|
280
|
+
allow();
|
|
281
|
+
}
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Language Bindings
|
|
285
|
+
|
|
286
|
+
### Python
|
|
287
|
+
|
|
288
|
+
The enum values are accessible as integers in the Python binding:
|
|
289
|
+
|
|
290
|
+
```python
|
|
291
|
+
import libinjection
|
|
292
|
+
|
|
293
|
+
result = libinjection.xss(test_input)
|
|
294
|
+
|
|
295
|
+
if result == -1: # LIBINJECTION_RESULT_ERROR
|
|
296
|
+
handle_error()
|
|
297
|
+
elif result == 1: # LIBINJECTION_RESULT_TRUE
|
|
298
|
+
block_request()
|
|
299
|
+
else: # result == 0, LIBINJECTION_RESULT_FALSE
|
|
300
|
+
allow_request()
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### PHP
|
|
304
|
+
|
|
305
|
+
```php
|
|
306
|
+
<?php
|
|
307
|
+
$result = libinjection_xss($input);
|
|
308
|
+
|
|
309
|
+
if ($result === -1) { // LIBINJECTION_RESULT_ERROR
|
|
310
|
+
handle_error();
|
|
311
|
+
} elseif ($result === 1) { // LIBINJECTION_RESULT_TRUE
|
|
312
|
+
block_request();
|
|
313
|
+
} else { // $result === 0, LIBINJECTION_RESULT_FALSE
|
|
314
|
+
allow_request();
|
|
315
|
+
}
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
### Lua
|
|
319
|
+
|
|
320
|
+
```lua
|
|
321
|
+
local libinjection = require "libinjection"
|
|
322
|
+
|
|
323
|
+
local result = libinjection.xss(input)
|
|
324
|
+
|
|
325
|
+
if result == -1 then -- LIBINJECTION_RESULT_ERROR
|
|
326
|
+
handle_error()
|
|
327
|
+
elseif result == 1 then -- LIBINJECTION_RESULT_TRUE
|
|
328
|
+
block_request()
|
|
329
|
+
else -- result == 0, LIBINJECTION_RESULT_FALSE
|
|
330
|
+
allow_request()
|
|
331
|
+
end
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
## Why This Change?
|
|
335
|
+
|
|
336
|
+
### The Problem with v3.x
|
|
337
|
+
|
|
338
|
+
In v3.x, when the parser encountered an invalid state (e.g., cursor position exceeding string length), it would call `assert()` or `abort()`, immediately terminating your entire process:
|
|
339
|
+
|
|
340
|
+
```c
|
|
341
|
+
// v3.x behavior (REMOVED in v4.0)
|
|
342
|
+
assert(hs->len >= hs->pos); // CRASH if violated
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
This was problematic for:
|
|
346
|
+
- **Web servers**: Malicious input could crash the server
|
|
347
|
+
- **Embedded systems**: Required high availability, no crashes
|
|
348
|
+
- **Production services**: Needed graceful degradation
|
|
349
|
+
|
|
350
|
+
### The Solution in v4.0
|
|
351
|
+
|
|
352
|
+
Parser errors now return `LIBINJECTION_RESULT_ERROR` instead of terminating:
|
|
353
|
+
|
|
354
|
+
```c
|
|
355
|
+
// v4.0 behavior
|
|
356
|
+
if (hs->len < hs->pos) {
|
|
357
|
+
return LIBINJECTION_RESULT_ERROR; // Graceful error return
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Your application can now:
|
|
362
|
+
- Log the error for debugging
|
|
363
|
+
- Continue running other requests
|
|
364
|
+
- Implement custom error policies
|
|
365
|
+
- Monitor error rates
|
|
366
|
+
|
|
367
|
+
## Need Help?
|
|
368
|
+
|
|
369
|
+
- **Issues**: https://github.com/libinjection/libinjection/issues
|
|
370
|
+
- **Pull Request**: https://github.com/libinjection/libinjection/pull/65
|
|
371
|
+
- **Documentation**: See README.md for updated examples
|
|
372
|
+
|
|
373
|
+
## Checklist
|
|
374
|
+
|
|
375
|
+
Use this checklist to verify your migration:
|
|
376
|
+
|
|
377
|
+
- [ ] Updated all `int` return types to `injection_result_t`
|
|
378
|
+
- [ ] Added `#include "libinjection_error.h"`
|
|
379
|
+
- [ ] Explicitly handle `LIBINJECTION_RESULT_ERROR` in all code paths
|
|
380
|
+
- [ ] Updated language binding code (if applicable)
|
|
381
|
+
- [ ] Added tests for error conditions
|
|
382
|
+
- [ ] Verified fail-safe behavior (block on error in security contexts)
|
|
383
|
+
- [ ] Updated logging/monitoring to track error rates
|
|
384
|
+
- [ ] Tested with edge cases (empty strings, very long inputs, etc.)
|
|
385
|
+
- [ ] Reviewed all `if (result)` checks for proper error handling
|
|
386
|
+
- [ ] Updated internal documentation and team guidelines
|
|
387
|
+
|
|
388
|
+
---
|
|
389
|
+
|
|
390
|
+
**Version**: 4.0.0
|
|
391
|
+
**Last Updated**: 2025
|
|
392
|
+
**Status**: Current
|
|
393
|
+
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
|
|
2
|
+
<img src="https://raw.githubusercontent.com/libinjection/libinjection/main/misc/libinjection.svg" width="70%">
|
|
3
|
+
|
|
4
|
+

|
|
5
|
+
[](https://raw.githubusercontent.com/libinjection/libinjection/main/COPYING)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
SQL / SQLI tokenizer parser analyzer. For
|
|
9
|
+
|
|
10
|
+
* C and C++
|
|
11
|
+
* [PHP](https://libinjection.client9.com/doc-sqli-php)
|
|
12
|
+
* [Python](https://libinjection.client9.com/doc-sqli-python)
|
|
13
|
+
* [Lua](/lua)
|
|
14
|
+
* [Java](https://github.com/jeonglee/Libinjection) (external port)
|
|
15
|
+
* [LuaJIT/FFI](https://github.com/p0pr0ck5/lua-ffi-libinjection) (external port)
|
|
16
|
+
|
|
17
|
+
See [https://www.client9.com/](https://www.client9.com/)
|
|
18
|
+
for details and presentations.
|
|
19
|
+
|
|
20
|
+
Simple example:
|
|
21
|
+
|
|
22
|
+
```c
|
|
23
|
+
#include <stdio.h>
|
|
24
|
+
#include <strings.h>
|
|
25
|
+
#include <errno.h>
|
|
26
|
+
#include "libinjection.h"
|
|
27
|
+
#include "libinjection_sqli.h"
|
|
28
|
+
|
|
29
|
+
int main(int argc, const char* argv[])
|
|
30
|
+
{
|
|
31
|
+
struct libinjection_sqli_state state;
|
|
32
|
+
injection_result_t result;
|
|
33
|
+
|
|
34
|
+
const char* input = argv[1];
|
|
35
|
+
size_t slen = strlen(input);
|
|
36
|
+
|
|
37
|
+
/* in real-world, you would url-decode the input, etc */
|
|
38
|
+
|
|
39
|
+
libinjection_sqli_init(&state, input, slen, FLAG_NONE);
|
|
40
|
+
result = libinjection_is_sqli(&state);
|
|
41
|
+
|
|
42
|
+
if (result == LIBINJECTION_RESULT_ERROR) {
|
|
43
|
+
fprintf(stderr, "error: parser encountered an error\n");
|
|
44
|
+
return 2;
|
|
45
|
+
} else if (result == LIBINJECTION_RESULT_TRUE) {
|
|
46
|
+
fprintf(stderr, "sqli detected with fingerprint of '%s'\n", state.fingerprint);
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/* LIBINJECTION_RESULT_FALSE - no SQLi detected */
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
$ gcc -Wall -Wextra examples.c libinjection_sqli.c
|
|
57
|
+
$ ./a.out "-1' and 1=1 union/* foo */select load_file('/etc/passwd')--"
|
|
58
|
+
sqli detected with fingerprint of 's&1UE'
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
More advanced samples:
|
|
62
|
+
|
|
63
|
+
* [sqli_cli.c](/src/sqli_cli.c)
|
|
64
|
+
* [reader.c](/src/reader.c)
|
|
65
|
+
* [fptool](/src/fptool.c)
|
|
66
|
+
|
|
67
|
+
VERSION INFORMATION
|
|
68
|
+
===================
|
|
69
|
+
|
|
70
|
+
See [CHANGELOG](CHANGELOG.md) for details.
|
|
71
|
+
|
|
72
|
+
Versions are listed as "major.minor.point"
|
|
73
|
+
|
|
74
|
+
Major are significant changes to the API and/or fingerprint format.
|
|
75
|
+
Applications will need recompiling and/or refactoring.
|
|
76
|
+
|
|
77
|
+
Minor are C code changes. These may include
|
|
78
|
+
* logical change to detect or suppress
|
|
79
|
+
* optimization changes
|
|
80
|
+
* code refactoring
|
|
81
|
+
|
|
82
|
+
Point releases are purely data changes. These may be safely applied.
|
|
83
|
+
|
|
84
|
+
ERROR HANDLING
|
|
85
|
+
==============
|
|
86
|
+
|
|
87
|
+
As of version 4.0.0, libinjection uses an `injection_result_t` enum for return values instead of `int`:
|
|
88
|
+
|
|
89
|
+
```c
|
|
90
|
+
typedef enum injection_result_t {
|
|
91
|
+
LIBINJECTION_RESULT_FALSE = 0, // No injection detected (benign input)
|
|
92
|
+
LIBINJECTION_RESULT_TRUE = 1, // Injection detected
|
|
93
|
+
LIBINJECTION_RESULT_ERROR = -1 // Parser error (invalid state)
|
|
94
|
+
} injection_result_t;
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
**Important:** Prior to v4.0.0, libinjection would call `abort()` and terminate the process when encountering parser errors. Now it returns `LIBINJECTION_RESULT_ERROR` instead, allowing your application to handle errors gracefully.
|
|
98
|
+
|
|
99
|
+
**Backward Compatibility:** The enum values `LIBINJECTION_RESULT_FALSE` (0) and `LIBINJECTION_RESULT_TRUE` (1) maintain backward compatibility with code that checks for true/false values. However, applications should be updated to handle `LIBINJECTION_RESULT_ERROR` (-1) to prevent treating parser errors as benign input.
|
|
100
|
+
|
|
101
|
+
**Migration:** See [MIGRATION.md](MIGRATION.md) for guidance on updating existing code.
|
|
102
|
+
|
|
103
|
+
QUALITY AND DIAGNOSITICS
|
|
104
|
+
========================
|
|
105
|
+
|
|
106
|
+
The continuous integration results at GitHub tests the following:
|
|
107
|
+
|
|
108
|
+
- [x] build and unit-tests under GCC
|
|
109
|
+
- [x] build and unit-tests under Clang
|
|
110
|
+
- [x] static analysis using [clang static analyzer](http://clang-analyzer.llvm.org)
|
|
111
|
+
- [x] static analysis using [cppcheck](https://github.com/danmar/cppcheck)
|
|
112
|
+
- [x] checks for memory errors using [valgrind](http://valgrind.org/)
|
|
113
|
+
|
|
114
|
+
LICENSE
|
|
115
|
+
=============
|
|
116
|
+
|
|
117
|
+
Copyright (c) 2012-2016, Nick Galbreath
|
|
118
|
+
Copyright (c) 2017-2024, libinjection Contributors
|
|
119
|
+
|
|
120
|
+
Licensed under the standard [BSD 3-Clause](http://opensource.org/licenses/BSD-3-Clause) open source
|
|
121
|
+
license. See [COPYING](/COPYING) for details.
|
|
122
|
+
|
|
123
|
+
## BUILD TARGETS
|
|
124
|
+
|
|
125
|
+
Some of the previous help runners have been merged into the Makefile. E.g.:
|
|
126
|
+
|
|
127
|
+
* run-clang-asan.sh -> `make clan-asan`
|
|
128
|
+
* make-ci.sh -> `make ci`
|
|
129
|
+
|
|
130
|
+
### Building and Installing Libraries
|
|
131
|
+
|
|
132
|
+
The autotools build system uses **libtool**, which places built libraries in the `src/.libs/` directory (not directly in `src/` like older versions).
|
|
133
|
+
|
|
134
|
+
**Basic build:**
|
|
135
|
+
```bash
|
|
136
|
+
./autogen.sh
|
|
137
|
+
./configure
|
|
138
|
+
make
|
|
139
|
+
|
|
140
|
+
# Built libraries are located at:
|
|
141
|
+
# - src/.libs/libinjection.a (static library)
|
|
142
|
+
# - src/.libs/libinjection.so (Linux shared) or src/.libs/libinjection.dylib (macOS shared)
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
**Building static libraries:**
|
|
146
|
+
```bash
|
|
147
|
+
./configure --enable-static
|
|
148
|
+
make
|
|
149
|
+
find . -name "*.a"
|
|
150
|
+
# Output: ./src/.libs/libinjection.a
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
**Installing to a specific location:**
|
|
154
|
+
```bash
|
|
155
|
+
./configure --prefix=/path/to/install
|
|
156
|
+
make
|
|
157
|
+
make install
|
|
158
|
+
|
|
159
|
+
# This installs:
|
|
160
|
+
# - Headers: /path/to/install/include/libinjection*.h
|
|
161
|
+
# - Libraries: /path/to/install/lib/libinjection.{a,so,dylib}
|
|
162
|
+
# - pkg-config: /path/to/install/lib/pkgconfig/libinjection.pc
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Linking against libinjection:**
|
|
166
|
+
|
|
167
|
+
Option 1 - Link against installed library (via pkg-config):
|
|
168
|
+
```bash
|
|
169
|
+
./configure --prefix=/usr/local
|
|
170
|
+
make install
|
|
171
|
+
gcc myapp.c $(pkg-config --cflags --libs libinjection)
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Option 2 - Link against build tree without installing:
|
|
175
|
+
```bash
|
|
176
|
+
gcc myapp.c -I/path/to/libinjection/src -L/path/to/libinjection/src/.libs -linjection
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Option 3 - Static linking from build tree:
|
|
180
|
+
```bash
|
|
181
|
+
gcc myapp.c -I/path/to/libinjection/src /path/to/libinjection/src/.libs/libinjection.a
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Migrating from Older Versions (client9/libinjection)
|
|
185
|
+
|
|
186
|
+
If you're upgrading from the old Makefile-based build system where `libinjection.a` was in `src/`, note that libraries are now in `src/.libs/`.
|
|
187
|
+
|
|
188
|
+
**Update your build scripts:**
|
|
189
|
+
|
|
190
|
+
For Makefiles:
|
|
191
|
+
```makefile
|
|
192
|
+
LIBINJECTION_DIR = ../libinjection
|
|
193
|
+
CFLAGS += -I$(LIBINJECTION_DIR)/src
|
|
194
|
+
LDFLAGS += -L$(LIBINJECTION_DIR)/src/.libs -linjection
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
For CMake:
|
|
198
|
+
```cmake
|
|
199
|
+
target_include_directories(myapp PRIVATE ../libinjection/src)
|
|
200
|
+
target_link_directories(myapp PRIVATE ../libinjection/src/.libs)
|
|
201
|
+
target_link_libraries(myapp injection)
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
If your build system requires libraries in a specific location:
|
|
205
|
+
```bash
|
|
206
|
+
./configure && make
|
|
207
|
+
cp src/.libs/libinjection.a /desired/location/
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
For more information, see:
|
|
211
|
+
- GNU Libtool documentation: https://www.gnu.org/software/libtool/manual/html_node/Linking-libraries.html
|
|
212
|
+
- GitHub issue #54
|
|
213
|
+
|
|
214
|
+
### Static Analysis
|
|
215
|
+
|
|
216
|
+
If you run `make cppcheck` you will see this warning printed:
|
|
217
|
+
```
|
|
218
|
+
nofile:0 information missingIncludeSystem Cppcheck cannot find all the include files (use --check-config for details)
|
|
219
|
+
```
|
|
220
|
+
You can safely ignore it as it is just saying that standard include files are being ignored (which is the recommended option):
|
|
221
|
+
```
|
|
222
|
+
example1.c:1:0: information: Include file: <stdio.h> not found. Please note: Cppcheck does not need standard library headers to get proper results. [missingIncludeSystem]
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
EMBEDDING
|
|
226
|
+
=============
|
|
227
|
+
|
|
228
|
+
The [src](/src)
|
|
229
|
+
directory contains everything, but you only need to copy the following
|
|
230
|
+
into your source tree:
|
|
231
|
+
|
|
232
|
+
* [src/libinjection.h](/src/libinjection.h)
|
|
233
|
+
* [src/libinjection_error.h](/src/libinjection_error.h)
|
|
234
|
+
* [src/libinjection_sqli.h](/src/libinjection_sqli.h)
|
|
235
|
+
* [src/libinjection_sqli.c](/src/libinjection_sqli.c)
|
|
236
|
+
* [src/libinjection_sqli_data.h](/src/libinjection_sqli_data.h)
|
|
237
|
+
* [COPYING](/COPYING)
|
|
238
|
+
|
|
239
|
+
For XSS detection, also copy:
|
|
240
|
+
|
|
241
|
+
* [src/libinjection_xss.h](/src/libinjection_xss.h)
|
|
242
|
+
* [src/libinjection_xss.c](/src/libinjection_xss.c)
|
|
243
|
+
* [src/libinjection_html5.h](/src/libinjection_html5.h)
|
|
244
|
+
* [src/libinjection_html5.c](/src/libinjection_html5.c)
|
|
245
|
+
|
|
246
|
+
The source includes a default version string (`"4.0.0"`).
|
|
247
|
+
You can override this at build time, for example by defining `LIBINJECTION_VERSION`:
|
|
248
|
+
|
|
249
|
+
```
|
|
250
|
+
CFLAGS="-DLIBINJECTION_VERSION=\"4.0.0-custom\""
|
|
251
|
+
```
|