Wapp

Check-in [15fbf713e6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Safety enhancements: (A) Invoke the application with the --lint option to do a self-check for unsafe constructs. (B) Bring back the wapp-unsafe command for the rare cases where it is actually needed. (C) Comment out wapp.tcl comment lines when building the wapptclsh application.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 15fbf713e692404a6fa09508a821351f9d5fd371380f791dcb572e515e68bd98
User & Date: drh 2018-02-01 03:11:55.580
Context
2018-02-01
03:45
Updates to the documentation. (check-in: c594b95816 user: drh tags: trunk)
03:11
Safety enhancements: (A) Invoke the application with the --lint option to do a self-check for unsafe constructs. (B) Bring back the wapp-unsafe command for the rare cases where it is actually needed. (C) Comment out wapp.tcl comment lines when building the wapptclsh application. (check-in: 15fbf713e6 user: drh tags: trunk)
2018-01-31
22:25
Fix typo in the shoplist.tcl app. (check-in: 0b681c21b4 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to README.md.
374
375
376
377
378
379
380






381
382
383
384
385
386
387
     Set _POLICY_ to "off" to completely disable the CSP mechanism.  Or
     specify some other policy suitable for the needs of the application.

  +  **wapp-debug-env**  
     This routine returns text that describes all of the Wapp parameters.
     Use it to get a parameter dump for troubleshooting purposes.








The following additional interfaces are envisioned, but are not yet
implemented:

  +  **wapp-send-hex** _HEX_  
     Cause the HTTP reply to be binary that is constructed from the
     hexadecimal text in the _HEX_ argument.  Whitespace in _HEX_ is ignored.







>
>
>
>
>
>







374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
     Set _POLICY_ to "off" to completely disable the CSP mechanism.  Or
     specify some other policy suitable for the needs of the application.

  +  **wapp-debug-env**  
     This routine returns text that describes all of the Wapp parameters.
     Use it to get a parameter dump for troubleshooting purposes.

  +  **wapp-unsafe** _TEXT_  
     Add _TEXT_ to the web page under construction even though _TEXT_ does
     contain TCL variable and command substitutions.  The application developer
     must ensure that the variable and command substitutions does not allow
     XSS attacks.  Avoid using this command.  The use of "wapp-subst" is 
     preferred in most situations.

The following additional interfaces are envisioned, but are not yet
implemented:

  +  **wapp-send-hex** _HEX_  
     Cause the HTTP reply to be binary that is constructed from the
     hexadecimal text in the _HEX_ argument.  Whitespace in _HEX_ is ignored.
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
     command is a no-op for short-lived CGI programs, obviously.  Also, this
     command should only be used during debugging, as otherwise it introduces
     a severe security vulnerability into the application.

The following interfaces are deprecated.  They currently exist for
compatibility but might disappear at any moment.

  +  **wapp-unsafe** _TEXT_  
     Add _TEXT_ to the web page under construction even though _TEXT_ does
     contain TCL variable and command substitutions.  The application developer
     must ensure that the variable and command substitutions does not allow
     XSS attacks.  Avoid using this command.  The use of "wapp-subst" is 
     preferred in most situations.

  +  **wapp-escape-html** _TEXT_  
     Add _TEXT_ to the web page under construction after first escaping any
     HTML markup contained with _TEXT_.  This command is equivalent to
     "wapp-subst {%html(_TEXT_)}".


  +  **wapp-escape-url** _TEXT_  







<
<
<
<
<
<
<







412
413
414
415
416
417
418







419
420
421
422
423
424
425
     command is a no-op for short-lived CGI programs, obviously.  Also, this
     command should only be used during debugging, as otherwise it introduces
     a severe security vulnerability into the application.

The following interfaces are deprecated.  They currently exist for
compatibility but might disappear at any moment.








  +  **wapp-escape-html** _TEXT_  
     Add _TEXT_ to the web page under construction after first escaping any
     HTML markup contained with _TEXT_.  This command is equivalent to
     "wapp-subst {%html(_TEXT_)}".


  +  **wapp-escape-url** _TEXT_  
Changes to mkccode.tcl.
60
61
62
63
64
65
66




67
68

69
70
71
72
73
74
75
    regsub {^\$HOME\y} $path $HOME path
    set in2 [open $path rb]
    puts "/* INCLUDE $path */"
    if {$instr} {
      while {1} {
        set line [gets $in2]
        if {[eof $in2]} break




        set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
        puts "\"$x\\n\""

      }
    } else {
      puts [read $in2]
    }
    puts "/* END $path */"
    close $in2
    continue







>
>
>
>
|
|
>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
    regsub {^\$HOME\y} $path $HOME path
    set in2 [open $path rb]
    puts "/* INCLUDE $path */"
    if {$instr} {
      while {1} {
        set line [gets $in2]
        if {[eof $in2]} break
        if {[regexp {^\s*#} $line]} {
          set x [string map {*/ *\\057} $line]
          puts "/* $x */"
        } else {
          set x [string map "\\\\ \\\\\\\\ \\\" \\\\\"" $line]
          puts "\"$x\\n\""
        }
      }
    } else {
      puts [read $in2]
    }
    puts "/* END $path */"
    close $in2
    continue
Changes to test01.tcl.
80
81
82
83
84
85
86



87
88
89
90
91
92
93
94
95
  wapp-set-cookie env-cookie full
  wapp "<h1>Wapp Full Environment</h1>\n"
  wapp-unsafe "<form method='POST' action='[wapp-param SELF_URL]'>\n"
  wapp "<input type='checkbox' name='var1'"
  if {[dict exists $wapp showhdr]} {
    wapp " checked"
  }



  wapp "> Var1\n"
  wapp "<input type='submit' name='s1' value='Go'>\n"
  wapp "<input type='hidden' name='hidden-parameter-1' "
  wapp "value='the long value / of ?$ hidden-1..<hi>'>\n"
  wapp "</form>"
  wapp "<pre>\n"
  foreach var [lsort [dict keys $wapp]] {
    if {$var==".reply"} continue
    wapp-escape-html "$var = [list [dict get $wapp $var]]\n\n"







>
>
>
|
|







80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
  wapp-set-cookie env-cookie full
  wapp "<h1>Wapp Full Environment</h1>\n"
  wapp-unsafe "<form method='POST' action='[wapp-param SELF_URL]'>\n"
  wapp "<input type='checkbox' name='var1'"
  if {[dict exists $wapp showhdr]} {
    wapp " checked"
  }
  # Deliberately unsafe calls to wapp-subst and wapp-trim, added here
  # to test wapp-safety-check
  #
  wapp-subst "> Var1\n"
  wapp-trim "<input type='submit' name='s1' value='Go'>\n"
  wapp "<input type='hidden' name='hidden-parameter-1' "
  wapp "value='the long value / of ?$ hidden-1..<hi>'>\n"
  wapp "</form>"
  wapp "<pre>\n"
  foreach var [lsort [dict keys $wapp]] {
    if {$var==".reply"} continue
    wapp-escape-html "$var = [list [dict get $wapp $var]]\n\n"
140
141
142
143
144
145
146


147


148
149
150
151
152
153
154
  }
  wapp-subst {</table>}
}
# Deliberately generate an error to test error handling.
proc wapp-page-errorout {} {
  wapp "<h1>Intentially generate an error</h1>\n"
  wapp "<p>This test should be ignored by the error handler\n"


  wapp $noSuchVariable


  wapp "<p>After the error\n"
}
proc wapp-page-csptest {} {
  wapp-allow-xorigin-params
  if {[wapp-param-exists csp]} {
    wapp-content-security-policy [wapp-param csp]
  }







>
>

>
>







143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
  }
  wapp-subst {</table>}
}
# Deliberately generate an error to test error handling.
proc wapp-page-errorout {} {
  wapp "<h1>Intentially generate an error</h1>\n"
  wapp "<p>This test should be ignored by the error handler\n"
  # The following line deliberately throws an error to test the
  # error recovering logic within Wapp
  wapp $noSuchVariable
  wapp "This is a $test of wapp-safety-check"
  wapp "This is another [test of] wapp-safety-check"
  wapp "<p>After the error\n"
}
proc wapp-page-csptest {} {
  wapp-allow-xorigin-params
  if {[wapp-param-exists csp]} {
    wapp-content-security-policy [wapp-param csp]
  }
Changes to wapp.tcl.
22
23
24
25
26
27
28
29
30
31















32
33
34
35
36


37
38
39
40
41
42
43
# procs during analysis.
#
proc wapp {txt} {
  global wapp
  dict append wapp .reply $txt
}

############################ Begin Deprecated Interfaces ######################
# Add text to the page under construction.  Do no escaping on the text.
#















proc wapp-unsafe {txt} {
  global wapp
  dict append wapp .reply $txt
}



# Append text after escaping it for HTML.
#
# The following commands are the same:
#
#      wapp-escape-html TEXT
#      wapp-subst %html(TEXT)
#







<


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>





>
>







22
23
24
25
26
27
28

29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# procs during analysis.
#
proc wapp {txt} {
  global wapp
  dict append wapp .reply $txt
}


# Add text to the page under construction.  Do no escaping on the text.
#
# Though "unsafe" in general, there are uses for this kind of thing.
# For example, if you want to return the complete, unmodified content of
# a file:
#
#         set fd [open content.html rb]
#         wapp-unsafe [read $fd]
#         close $fd
#
# You could do the same thing using ordinary "wapp" instead of "wapp-unsafe".
# The difference is that wapp-safety-check will complain about the misuse
# of "wapp", but it assumes that the person who write "wapp-unsafe" understands
# the risks.
#
# Though occasionally necessary, the use of this interface should be minimized.
#
proc wapp-unsafe {txt} {
  global wapp
  dict append wapp .reply $txt
}


############################ Begin Deprecated Interfaces ######################
# Append text after escaping it for HTML.
#
# The following commands are the same:
#
#      wapp-escape-html TEXT
#      wapp-subst %html(TEXT)
#
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
    dict unset wapp .csp
  } else {
    dict set wapp .csp $val
  }
}

# Examine the bodys of all procedures in this program looking for
# unsafe calls to "wapp".  Return a text string containing warnings.
# Return an empty string if all is ok.
#
# This routine is advisory only.  It misses some constructs that are
# dangerous and flags others that are safe.
#
proc wapp-safety-check {} {
  set res {}
  foreach p [info procs] {
    set ln 0
    foreach x [split [info body $p] \n] {
      incr ln
      if {[regexp {^[ \t]*wapp[ \t]+([^\n]+)} $x all tail]
       && [string index $tail 0]!="\173"
       && [regexp {[[$]} $tail]
      } {
        append res "$p:$ln: unsafe \"wapp\" call: \"[string trim $x]\"\n"
      }
      if {[regexp {^[ \t]*wapp-subst[ \t]+[^\173]} $x]} {
        append res "$p:$ln: unsafe \"wapp-subst\" call: \"[string trim $x]\"\n"
      }
    }
  }
  return $res
}

# Return a string that descripts the current environment.  Applications







|
|
















|
|







302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
    dict unset wapp .csp
  } else {
    dict set wapp .csp $val
  }
}

# Examine the bodys of all procedures in this program looking for
# unsafe calls to various Wapp interfaces.  Return a text string
# containing warnings. Return an empty string if all is ok.
#
# This routine is advisory only.  It misses some constructs that are
# dangerous and flags others that are safe.
#
proc wapp-safety-check {} {
  set res {}
  foreach p [info procs] {
    set ln 0
    foreach x [split [info body $p] \n] {
      incr ln
      if {[regexp {^[ \t]*wapp[ \t]+([^\n]+)} $x all tail]
       && [string index $tail 0]!="\173"
       && [regexp {[[$]} $tail]
      } {
        append res "$p:$ln: unsafe \"wapp\" call: \"[string trim $x]\"\n"
      }
      if {[regexp {^[ \t]*wapp-(subst|trim)[ \t]+[^\173]} $x all cx]} {
        append res "$p:$ln: unsafe \"wapp-$cx\" call: \"[string trim $x]\"\n"
      }
    }
  }
  return $res
}

# Return a string that descripts the current environment.  Applications
369
370
371
372
373
374
375










376
377
378
379
380
381
382
      -trace {
        proc wappInt-trace {} {
          set q [wapp-param QUERY_STRING]
          set uri [wapp-param BASE_URL][wapp-param PATH_INFO]
          if {$q!=""} {append uri ?$q}
          puts $uri
        }










      }
      -D*=* {
        if {[regexp {^.D([^=]+)=(.*)$} $term all var val]} {
          set ::$var $val
        }
      }
      default {







>
>
>
>
>
>
>
>
>
>







385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
      -trace {
        proc wappInt-trace {} {
          set q [wapp-param QUERY_STRING]
          set uri [wapp-param BASE_URL][wapp-param PATH_INFO]
          if {$q!=""} {append uri ?$q}
          puts $uri
        }
      }
      -lint {
        set res [wapp-safety-check]
        if {$res!=""} {
          puts "Potential problems in this code:"
          puts $res
          exit 1
        } else {
          exit
        }
      }
      -D*=* {
        if {[regexp {^.D([^=]+)=(.*)$} $term all var val]} {
          set ::$var $val
        }
      }
      default {