Hex-encoded DB keys to avoid subdirectory escape attacks

This commit is contained in:
Tony Garnock-Jones 2015-09-23 22:01:45 -04:00
parent b7bccd00a6
commit be6987c1eb

View File

@ -9,6 +9,7 @@
db-keys) db-keys)
(require racket/file) (require racket/file)
(require file/sha1)
(struct db (name path serializer deserializer) #:transparent) (struct db (name path serializer deserializer) #:transparent)
@ -20,27 +21,32 @@
(unless (string? key) (unless (string? key)
(error what "Invalid key for db ~a: ~v" (db-name db) key))) (error what "Invalid key for db ~a: ~v" (db-name db) key)))
(define (db-has-key? db key) ;; We avoid potential filesystem subdirectory escape attacks by
(check-key 'db-has-key? db key) ;; encoding key paths into hex. Special characters in keys are thus
(file-exists? (build-path (db-path db) key))) ;; permitted and rendered harmless.
(define (key->path what db key)
(check-key what db key)
(build-path (db-path db) (bytes->hex-string (string->bytes/utf-8 key))))
(define (db-ref db key default-thunk) (define (db-has-key? db key)
(check-key 'db-ref db key) (file-exists? (key->path 'db-has-key? db key)))
(define p (build-path (db-path db) key))
(if (file-exists? p) (define (db-ref db key default)
((db-deserializer db) (file->value p)) (define p (key->path 'db-ref db key))
(default-thunk))) (cond
[(file-exists? p) ((db-deserializer db) (file->value p))]
[(procedure? default) (default)]
[else default]))
(define (db-set! db key value) (define (db-set! db key value)
(check-key 'db-set! db key) (define p (key->path 'db-set! db key))
(write-to-file value (build-path (db-path db) key) (write-to-file ((db-serializer db) value) p #:exists 'replace))
#:exists 'replace))
(define (db-remove! db key) (define (db-remove! db key)
(check-key 'db-remove! db key) (define p (key->path 'db-remove! db key))
(define p (build-path (db-path db) key))
(when (file-exists? p) (when (file-exists? p)
(delete-file p))) (delete-file p)))
(define (db-keys db) (define (db-keys db)
(map path->string (directory-list (db-path db)))) (map (lambda (p) (bytes->string/utf-8 (hex-string->bytes (path->string p))))
(directory-list (db-path db))))