ksgi

Форк
0
/
tutorial6.xml 
244 строки · 9.4 Кб
1
<article data-sblg-article="1" data-sblg-tags="tutorial" itemscope="itemscope" itemtype="http://schema.org/BlogPosting">
2
	<header>
3
		<h2 itemprop="name">
4
			Best practises for <a href="https://man.openbsd.org/pledge.2">pledge(2)</a> security
5
		</h2>
6
		<address itemprop="author"><a href="https://github.com/kristapsdz">Kristaps Dzonsons</a></address>
7
		<time itemprop="datePublished" datetime="2018-04-06">6 April, 2018</time>
8
	</header>
9
	<p>
10
		<aside itemprop="about">
11
			Let's set the record straight for securing <span class="nm">kcgi</span> CGI and FastCGI applications with <a
12
				href="https://man.openbsd.org/pledge.2">pledge(2)</a>.
13
			This is focussed on secure <a href="https://www.openbsd.org">OpenBSD</a> deployments.
14
		</aside>
15
	</p>
16
	<h3>
17
		Theory
18
	</h3>
19
	<p>
20
		Internally, <span class="nm">kcgi</span> makes considerable use of available security tools.
21
		But it's also designed to be invoked in a secure environment.
22
		We'll start with <a href="https://man.openbsd.org/pledge.2">pledge(2)</a>, which has been around on <a
23
			href="https://www.openbsd.org">OpenBSD</a> since version 5.9.
24
		If you're reading this tutorial, you're probably on <a href="https://www.openbsd.org">OpenBSD</a>, and you probably have
25
		knowledge of <a href="https://man.openbsd.org/pledge.2">pledge(2)</a>.
26
	</p>
27
	<p>
28
		How to begin?
29
		Read <a href="kcgi.3.html">kcgi(3)</a>.
30
		It includes canonical information on which <a href="https://man.openbsd.org/pledge.2">pledge(2)</a> promises you'll need for
31
		each function in the library.
32
		This is just a tutorial&#8212;the manpage is canonical and overrides what you may read here.
33
	</p>
34
	<p>
35
		Next, assess the promises that your application needs.
36
		From  <a href="kcgi.3.html">kcgi(3)</a>, it's easy to see which promises we'll need to start.
37
		You'll need to augment this list with whichever tools you're also using.
38
		The general push is to start with the broadest set of required promises, then restrict as quickly as possible.
39
		Sometimes this can be done in a single  <a href="https://man.openbsd.org/pledge.2">pledge(2)</a>, but other times it takes a
40
		few.
41
	</p>
42
	<figure>
43
		<img class="tall" src="tutorial6.svg" alt="" />
44
	</figure>
45
	<h3>
46
		Source Code: CGI
47
	</h3>
48
	<p>
49
		Let's start with a trivial CGI application.
50
		This parses the HTTP context with <a href="khttp_parse.3.html">khttp_parse(3)</a>, then emits output using the writing
51
		functions.
52
		Most applications will perform some sort of work based upon the context, such as with form input, but it's irrelevant for the
53
		purposes of explanation.
54
	</p>
55
	<p>
56
		I avoid error checking for brevity, but <strong>each function needs to be checked for return values</strong>.
57
		This goes for all examples, all the time!
58
	</p>
59
	<figure class="sample">
60
		<pre class="prettyprint linenums">#include &lt;sys/types.h&gt; /* size_t, ssize_t */
61
#include &lt;stdarg.h&gt; /* va_list */
62
#include &lt;stddef.h&gt; /* NULL */
63
#include &lt;stdint.h&gt; /* int64_t */
64
#include &lt;kcgi.h&gt;
65

66
int 
67
main(void) {
68
    struct kreq r;
69
    const char *const pages[1] = { "index" };
70

71
    if (khttp_parse(&amp;r, NULL, 0, pages, 1, 0) != KCGI_OK)
72
        return 0;
73
    khttp_head(&amp;r, kresps[KRESP_STATUS], 
74
        "%s", khttps[KHTTP_200]);
75
    khttp_head(&amp;r, kresps[KRESP_CONTENT_TYPE], 
76
        "%s", kmimetypes[KMIME_TEXT_PLAIN]);
77
    khttp_body(&amp;r);
78
    khttp_puts(&amp;r, "Hello, world!\n");
79
    khttp_free(&amp;r);
80
    return 0;
81
}</pre>
82
	</figure>
83
	<p>
84
		Obviously, this does very little.
85
		And that's fine, because <a href="https://man.openbsd.org/pledge.2">pledge(2)</a> doesn't really care about how complex your
86
		application is&#8212;just which system resources are used.
87
		Our main focus is going to be <a href="khttp_parse.3.html">khttp_parse(3)</a>, which requires the system resources to create
88
		its parsing contexts and safely get our data extracted and processed.
89
		After that, all we're doing is constructing a response.
90
	</p>
91
	<p>
92
		To use this security tool, all we need is to include <code>&lt;unistd.h&gt;</code> and to understand the <a
93
			href="https://man.openbsd.org/pledge.2">pledge(2)</a> system call.
94
		We'll start with the most significant protection: by constraining our application after the context has been parsed.
95
	</p>
96
	<figure class="sample">
97
		<pre class="prettyprint linenums">if (khttp_parse(&amp;r, NULL, 0, pages, 1, 0) != KCGI_OK)
98
    return 0;
99
if (pledge("stdio", NULL) == -1)
100
    return 0;</pre>
101
	</figure>
102
	<p>
103
		This <a href="https://man.openbsd.org/pledge.2">pledge(2)</a> promise restricts the process to simply using available I/O
104
		channels.
105
		The only <span class="nm">kcgi</span> functions requiring more than <code>"stdio"</code> are the file-based template functions
106
		described in <a href="khttp_template.3.html">khttp_template(3)</a> and <a href="khttp_template.3.html">khttp_templatex(3)</a>,
107
		which also require <code>"rpath"</code>.
108
	</p>
109
	<p>
110
		We can further secure our systems by pushing  <a href="https://man.openbsd.org/pledge.2">pledge(2)</a> <em>before</em> the call
111
		to  <a href="khttp_parse.3.html">khttp_parse(3)</a>.
112
		The only promises <a href="khttp_parse.3.html">khttp_parse(3)</a> requires are to <a
113
			href="https://man.openbsd.org/fork.2">fork(2)</a> its internal handlers.
114
	</p>
115
	<figure class="sample">
116
		<pre class="prettyprint linenums">if (pledge("stdio proc", NULL) == -1)
117
    return 0;
118
if (khttp_parse(&amp;r, NULL, 0, pages, 1, 0) != KCGI_OK)
119
    return 0;
120
if (pledge("stdio", NULL) == -1)
121
    return 0;</pre>
122
	</figure>
123
	<p>
124
		Or if one is using <a href="khttp_template.3.html">khttp_template(3)</a> to marshall a response:
125
	</p>
126
	<figure class="sample">
127
		<pre class="prettyprint linenums">if (pledge("stdio rpath proc", NULL) == -1)
128
    return 0;
129
if (khttp_parse(&amp;r, NULL, 0, pages, 1, 0) != KCGI_OK)
130
    return 0;
131
if (pledge("stdio rpath", NULL) == -1)
132
    return 0;</pre>
133
	</figure>
134
	<p>
135
		That's it!
136
		Obviously, you'll need to expand the set of promises proportionate to your application's needs.
137
		Let's put it all together:
138
	</p>
139
	<figure class="sample">
140
		<pre class="prettyprint linenums">#include &lt;sys/types.h&gt; /* size_t, ssize_t */
141
#include &lt;stdarg.h&gt; /* va_list */
142
#include &lt;stddef.h&gt; /* NULL */
143
#include &lt;stdint.h&gt; /* int64_t */
144
#include &lt;unistd.h&gt; /* pledge */
145
#include &lt;kcgi.h&gt;
146

147
int 
148
main(void) {
149
    struct kreq r;
150
    const char *const pages[1] = { "index" };
151

152
    if (pledge("stdio proc", NULL) == -1)
153
        return 0;
154
    if (khttp_parse(&amp;r, NULL, 0, pages, 1, 0) != KCGI_OK)
155
        return 0;
156
    if (pledge("stdio", NULL) == -1)
157
        return 0;
158
    khttp_head(&amp;r, kresps[KRESP_STATUS], 
159
        "%s", khttps[KHTTP_200]);
160
    khttp_head(&amp;r, kresps[KRESP_CONTENT_TYPE], 
161
        "%s", kmimetypes[KMIME_TEXT_PLAIN]);
162
    khttp_body(&amp;r);
163
    khttp_puts(&amp;r, "Hello, world!\n");
164
    khttp_free(&amp;r);
165
    return 0;
166
}</pre>
167
	</figure>
168
	<p>
169
		One last note: portability.
170
		If you're going to be writing CGI scripts that must be portable across architectures, consider using
171
		<a href="https://github.com/kristapsdz/oconfigure">oconfigure</a> for a selection of portable OpenBSD functions and feature tests.
172
	</p>
173
	<h3>
174
		Source Code: FastCGI
175
	</h3>
176
	<p>
177
		This follows the logic of the CGI example, but we need to have extra promises to account for the increased complexity of FastCGI processing.
178
		First, start with our simple example without any header inclusions&#8212;all of which are the same as in the CGI example.
179
	</p>
180
	<p>
181
		Again, <strong>each function needs to be checked for return values</strong>.
182
		This would otherwise clutter up the examples, but production systems <strong>must</strong> error check.
183
	</p>
184
	<figure class="sample">
185
		<pre class="prettyprint linenums">int 
186
main(void) {
187
    struct kreq r;
188
    const char *const pages[1] = { "index" };
189
    struct kfcgi *fcgi;
190
    enum kcgi_err er;
191

192
    if (khttp_fcgi_init(&amp;fcgi, NULL, 0, pages, 1, 0) != KCGI_OK)
193
        return 0;
194
    for (;;) {
195
        if (khttp_fcgi_parse(fcgi, &amp;req) != KCGI_OK)
196
            break;
197
        khttp_head(&amp;r, kresps[KRESP_STATUS], 
198
            "%s", khttps[KHTTP_200]);
199
        khttp_head(&amp;r, kresps[KRESP_CONTENT_TYPE], 
200
            "%s", kmimetypes[KMIME_TEXT_PLAIN]);
201
        khttp_body(&amp;r);
202
        khttp_puts(&amp;r, "Hello, world!\n");
203
        khttp_free(&amp;r);
204
    }
205
    return 0;
206
}</pre>
207
	</figure>
208
	<p>
209
		The FastCGI-specific functions we need to manage are
210
		<a href="khttp_fcgi_init.3.html">khttp_fcgi_init(3)</a> and
211
		<a href="khttp_fcgi_parse.3.html">khttp_fcgi_parse(3)</a>.
212
		The promises required are all noted in <a href="kcgi.3.html">kcgi(3)</a>.
213
		The rest follow from the CGI example.
214
	</p>
215
	<figure class="sample">
216
		<pre class="prettyprint linenums">int 
217
main(void) {
218
    struct kreq r;
219
    const char *const pages[1] = { "index" };
220
    struct kfcgi *fcgi;
221
    enum kcgi_err er;
222

223
    if (pledge("unix sendfd recvfd proc stdio", NULL) == -1)
224
        return 0;
225
    if (khttp_fcgi_init(&amp;fcgi, NULL, 0, pages, 1, 0) != KCGI_OK)
226
        return 0;
227
    if (pledge("stdio recvfd", NULL) == -1)
228
        return 0;
229
    for (;;) {
230
        if (khttp_fcgi_parse(fcgi, &amp;req) != KCGI_OK)
231
            break;
232
        khttp_head(&amp;r, kresps[KRESP_STATUS], 
233
            "%s", khttps[KHTTP_200]);
234
        khttp_head(&amp;r, kresps[KRESP_CONTENT_TYPE], 
235
            "%s", kmimetypes[KMIME_TEXT_PLAIN]);
236
        khttp_body(&amp;r);
237
        khttp_puts(&amp;r, "Hello, world!\n");
238
        khttp_free(&amp;r);
239
    }
240
    khttp_fcgi_free(fcgi);
241
    return 0;
242
}</pre>
243
	</figure>
244
</article>
245

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.