do=goto leaks page existence
[ikiwiki.git] / doc / todo / Zoned_ikiwiki.mdwn
1 [[!toc levels=3]]
2
3 # Zoned ikiwiki
4
5 ## The idea
6
7 The idea behind this would be to have one ikiwiki behave as a dynamic private wiki in a specified area
8 and a more static publiczone wiki.
9
10 ## Use cases
11
12 This can be more or less difficult depending on the use case.
13
14 ### Purely static public zone with a single, controlled-access inward zone
15
16 For this case, only a known set of people are authorized to see the inward zone
17 or edit anything. Everybody else sees only the public zone. This use case is mostly
18 easy to handle now, as long as access to things like the `recentchanges` page and
19 repository browser are not granted for the public zone. In particular, the features
20 that allow information exposure via edit access are not of concern in this case.
21
22 ### Static public zone, more than one controlled inward zone
23
24 In this case, the known, controlled set of people with special access are divided
25 into groups with access to different (or overlapping) zones. The public still sees only a static zone.
26
27 Here, some of the harder issues, like information disclosure via edit access, do apply,
28 but only to members of the known, controlled groups. How much of a problem that is
29 depends on _how sensitive_ the information is that each group might reveal from another
30 zone. The rcs logs will show when a page has been edited to contain an [[ikiwiki/directive/inline]]
31 directive or other trick to reveal information, so if it is enough to treat the trusted users' conduct
32 as a management issue ("don't do that, please") then the risks can be acceptable in this case.
33
34 ### Public zone allows contribution/editing by external users
35
36 This case is the most difficult to cover at present, and probably shouldn't be attempted
37 without solutions to most or all of the **obstacles** identified here. 
38
39 ## Implementation techniques
40
41 ### Edit control by user and pagespec: lockedit
42
43 This works today, using the [[plugins/lockedit]] plugin. Because the `user` predicate
44 can be part of a [[ikiwiki/PageSpec]], this is all we need to flexibly control edit access
45 using any authentication method `ikiwiki` supports.
46
47 ### View control in the `http` server
48
49 We already can more or less do this for example with [[httpauth|/plugins/httpauth/]], `.htaccess` files and a proper `httpauth_pagespec`.
50
51 _Drawbacks:_ might be fiddly to configure and require maintaining two different user/pass logbases (native ikiwiki
52 signin), or impractical if ikiwiki is using an authentication method not natively supported
53 in the `http` server (e.g., OpenID).
54
55 ### View control in ikiwiki CGI
56
57 By requiring access to private zones to go through an ikiwiki CGI wrapper,
58 any ikiwiki-supported authentication method can be used, and the accessible
59 pages can be specified using the `user` predicate with [[ikiwiki/PageSpec]]s,
60 just as with the [[plugins/lockedit]] plugin.
61
62 The [[plugins/contrib/signinview]] plugin implements this idea, using very
63 simple configuration that is possible even in shared-hosting environments
64 without complete access to the `http` server configuration, as long as
65 `.htaccess` files or their equivalent can be created. The top directory of
66 a private zone needs only a `.htaccess` file with `Deny from All` or
67 `Require all denied` (or other equivalent directive for the `http` server
68 in use), and a `403` error handler of `{$cgiurl}?do=view`.
69
70 The plugin emits response headers intended to discourage non-private caches
71 from retaining the retrieved content. (They are already supposed to avoid
72 caching any response to a request with an `Authorization` header, but this
73 plugin can be used with any ikiwiki-supported auth method, not all of which
74 require that header.)
75
76 A plugin like [[plugins/contrib/pagespec_alias]] can be very useful for
77 defining a group of authorized users:
78
79     us: user(alice) or user(bob) or user(clotaldo)
80
81 so that zone access can be a simple [[ikiwiki/PageSpec]]:
82
83     us() and ours/*
84
85 *Drawbacks:* The private zones no longer reap all the benefits of a static
86 wiki generator, as a (fairly heavy) ikiwiki CGI wrapper must be started for
87 each access. (On the other hand, all it needs to do after confirming authorization
88 is basically `cat` the statically-generated page with appropriate response headers,
89 keeping the code simple and easy to audit.)
90
91 This can be adequate for a case where the static, public zone could receive a lot
92 of traffic, with the private zone(s) accessed only by a known small group of people.
93
94 ### View control with a FastCGI Authorizer
95
96 A plugin implementing a [FastCGI](http://www.fastcgi.com/)
97 [Authorizer](http://www.fastcgi.com/drupal/node/6?q=node/22#S6.3) could provide
98 the same benefits as [[plugins/contrib/signinview]] (any ikiwiki-supported auth
99 method, simple zone definition with [[ikiwiki/PageSpec]]s) with less overhead
100 per access. It would also be simpler than [[plugins/contrib/signinview]] by
101 leaving it as the `http` server's responsibility to generate the proper headers
102 and serve the content.
103
104 Caching proxies are already supposed to avoid caching any response to a request
105 that included an `Authorization` header. For some ikiwiki-supported auth methods,
106 that header might not be needed in the request, and care may be needed to configure
107 the server to emit other necessary response headers to discourage caching of
108 content from a private zone.
109
110 *Drawbacks:* Not yet implemented, someone would have to do it.
111 It's not clear [[what code changes fastcgi|todo/fastcgi or modperl installation instructions]]
112 would require in ikiwiki. An Authorizer seems like a good place to start because of its
113 limited, simple functionality--but as it could make use of any ikiwiki-supported auth method,
114 evaluate `PageSpec`s, and the like, it could still run a non-trivial amount of the code.
115
116 ## Obstacles
117
118 A number of ikiwiki features aren't (yet) designed with zoning in mind,
119 and it will take some effort both to identify them all, and to think out how they
120 could be addressed. This section invites brainstorming of both kinds.
121 This might eventually merit a separate page [[Zoned ikiwiki obstacles]]
122 but I'll begin it here.
123
124 Note that not all of these issues will be problems for all **zoned ikiwiki use cases**.
125
126 ### Leakage of page existence by `do=goto`
127
128 An unauthorized client can use a `do=goto` request to find out whether a
129 page exists (will be forbidden to view it) or not (will be forbidden to create it).
130
131 My first idea was to fix this all within [[plugins/contrib/signinview]] by hooking
132 `cgi` first and checking for `goto` and an unauthorized page. But checking authorization
133 requires session info, not loaded at `cgi` hook time. Next idea was to somehow skip the rest of
134 the chain of `cgi` hooks, preventing `goto` from handling the request, and handling
135 it again in `sessioncgi`. But 'skip the rest of this chain' doesn't seem to be something
136 a hook can return.
137
138 Hmm, maybe change the `do` parameter to something other than `goto` before the `goto` hook
139 can see it, _then_ handle it later in `sessioncgi`?
140
141 ### Backlinks
142
143 What is problematic is when you link a public page in a private page : 
144 a backlink will be generated from the public page to the private page.
145
146 As noted in [[per_page_ACLs]] in the end users through backlink 
147 navigation will frequently hit HTTP/401 deterring browsing as well as for the admin at false-positive logwatching.
148
149 One can radically [[disable backlinks feature|todo/allow_disabling_backlinks]] but then no more neat backlink navigation that
150 is really good to have in both area.
151
152 Another way of just preventing this backlink leak in that case would be sufficient via i.e a *privatebacklinks* config and
153 a patch like this one [[!toggle id="backlinkpatch" text="(show)"]].
154
155 [[!toggleable id="backlinkpatch" text="""
156 Comments are welcome.
157
158 [[mathdesc]]
159
160
161 <pre>
162 diff --git a/IkiWiki.pm b/IkiWiki.pm
163 --- a/IkiWiki.pm
164 +++ b/IkiWiki.pm
165 @@ -294,6 +294,14 @@ sub getsetup () {
166                 safe => 1,
167                 rebuild => 1,
168         },
169 +       privatebacklinks => {
170 +               type => "pagespec",
171 +               example => "",
172 +               description => "PageSpec controlling which backlinks are private (ie users/*)",
173 +               link => "ikiwiki/PageSpec",
174 +               safe => 1,
175 +               rebuild => 1,
176 +       },
177         hardlink => {
178                 type => "boolean",
179                 default => 0,
180 diff --git a/IkiWiki/Render.pm b/IkiWiki/Render.pm
181 --- a/IkiWiki/Render.pm
182 +++ b/IkiWiki/Render.pm
183 @@ -52,7 +52,8 @@ sub backlinks ($) {
184                         $p_trimmed=~s/^\Q$dir\E// &&
185                         $page_trimmed=~s/^\Q$dir\E//;
186                                
187 -               push @links, { url => $href, page => pagetitle($p_trimmed) };
188 +               push @links, { url => $href, page => pagetitle($p_trimmed) }
189 +               unless defined $config{privatebacklinks} && length $config{privatebacklinks} && pagespec_match($p, $config{privatebacklinks}) && !pagespec_match($page, $config{privatebacklinks}) ;
190         }
191         return @links;
192  }
193
194 </pre>
195 """]]
196
197 In use cases where the main concern about backlinks is only the bad user experience when links are
198 shown that lead to access denial when clicked, a workable
199 solution could be to make the backlinks `div` invisible in `local.css`.
200
201 ### recentchanges page
202
203 An accessible `recentchanges` page can include links to changes to pages
204 that should not be accessible. Even if the links cannot be followed, the
205 existence of the pages and their edit history are leaked. If rcs integration
206 is configured, those links on the `recentchanges` page can leak complete contents
207 through the **rcs browser**.
208
209 It can be helpful to generate separate `recentchanges` pages for different zones.
210 The [[plugins/recentchanges]] plugin already allows this--a `recentchanges` page
211 can be created anywhere, just by using the `recentchanges` directive
212 with the right [[ikiwiki/PageSpec]] for the zone it should cover--except that it cannot yet
213 be configured to generate a different `recentchanges` link destination into pages
214 in different zones. So, it would be helpful if its configuration could allow multiple
215 `recentchangespage` values, paired with `PageSpec`s for the pages on which they
216 should be used.
217
218 ### rcs browser
219
220 If the repository browser is accessible, potentially all content can be exposed.
221 Even if links to the repository browser are not generated into public wiki pages,
222 if a user can obtain or guess the repository browser URL and construct arbitrary
223 requests, information can be revealed.
224
225 Solutions could involve authnz features of the revision control systems themselves
226 and their associated repository browsers; for example, `svn` supposedly has such
227 features, and recent versions of `viewvc` supposedly honor them. But such features
228 may not be available for every rcs, and where they are available, they'll have to
229 be configured separately and differently from ikiwiki itself. They might not support
230 the same auth methods (e.g. OpenID) being used by the wiki itself.
231
232 Another approach would be for ikiwiki's own rcs plugin to generate a CGI wrapper
233 that invokes the repository browser CGI (which itself would _not_ be made
234 executable via `http` request). The `historyurl` and `diffurl` would then refer
235 to this wrapper. (In fact, they would not have to be specified in the config file,
236 as the plugin would know where it generated them. Instead, what would need to be
237 specified would be the filesystem path for the rcs browser being wrapped). The
238 wrapper could dissect the request parameters, identify the pages being accessed,
239 and subject them to the same accessibility tests used for the wiki. The rcs browser
240 itself needs to be configured to use the wrapper URL in all its generated links,
241
242 This might not be very hard to do with `gitweb` as it is already implemented in Perl.
243 The wrapper could probably import it and use its already-supplied routines to parse
244 the request into the affected file names, and probably complete the whole request
245 without a second `exec`. Other rcs backends might or might not be as easy.
246
247 ### Search
248
249 If [[plugins/search]] is enabled, private content is indexed and
250 searchable to the public.
251
252 ### Information leaks allowed by edit access
253
254 > Have you considered all the ways that anyone with edit access to the
255 > public wiki could expose information from the public wiki? For example,
256 > you could inline all the private pages into a public page. --[[Joey]]
257
258 Many ikiwiki features could give information exposure opportunities to someone
259 with edit access. The list here is surely incomplete, and would take a purposeful
260 review of the code and plugins (including third-party plugins) to complete.
261
262 * Directives that can inline information from other pages
263     * [[ikiwiki/directive/inline]] *the most obvious one*
264     * [[ikiwiki/directive/map]]
265     * [[ikiwiki/directive/brokenlinks]] ?
266     * [[ikiwiki/directive/orphans]] ?
267     * [[ikiwiki/directive/linkmap]] ?
268     * _others_?
269 * Not to forget `contrib` plugins
270     * [[plugins/contrib/report]] ?
271     * _others_?
272
273 Note that, _with_ the right controls on who can edit the pages and insert
274 the directives, the fact that a public page can inline stuff from private
275 pages can be very useful. Public pages can be created that are populated
276 by selected content that's maintained on the private side. The [[ikiwiki/directive/if]]
277 directive can be used in the private content to control what parts can be
278 inlined into public pages. All of this is in ikiwiki today.