Does anybody know if a sort of SQL-like security of Prolog database has been
ever implemented somehow?
As I am interested in "Prolog and the Web", I argue that securing of
modules/predicates is mandatory.
I guess that this would be reasonably easy to implement for Prolog systems
developers.
As a starting point, I think that a simple hook into prolog calls (i.e. the
possibility to intercept *any* call) should be enough to implement
assert/retract as well as call permissions.
Any insight?
Thank you very much.
M
I'm working with Torbjorn Lager on a thing called SWAPP. In a
nutshell, the idea is to provide a RESTful API to Prolog where the
user can post logical theories (Prolog programs) and query them. The
result is sent as JSON.
We solve the security by analysing the possible call-tree and checking
that against a white-list.
Intercepting all calls is possible in SWI-Prolog by means of the tracer
hook, but you probably get better results doing full meta-interpretation.
Program analysis of course also costs time, but at least doesn't affect
runtime and the results can be cached (not implemented yet).
The current state (though far from complete and surely the safety needs
more checking and thought) is at
http://www.swi-prolog.org/git/contrib/SWAPP.git
(requires the current GIT version of SWI-Prolog 5.9.8 due to a mistake
in the predicate-property declaration for retract/1 in older versions.
Older versions consider retract/1 always unsafe, while we consider it
safe if we can prove that the argument is not module-qualified and
therefore does not retract outside the current module).
Cheers --- Jan
Logtalk, which you can run with most Prolog compilers, enforces
predicate scope directives (predicates can be declared public,
protected, or private) and provides a secure implementation of meta-
predicates.
> I guess that this would be reasonably easy to implement for Prolog systems
> developers.
Easy, yes. The problem is that most Prolog implementers don't want to
break compatibility with existing code.
> As a starting point, I think that a simple hook into prolog calls (i.e. the
> possibility to intercept *any* call) should be enough to implement
> assert/retract as well as call permissions.
>
> Any insight?
As Jan suggested, you can define a meta-predicate that takes as
argument a call and meta-interprets it in order to check is safety.
Cheers,
Paulo
actually I was thinking to a sort of user-dependent privileges on Prolog
database.
As a very simple sketch, you can consider a user/4 predicate:
user(ID, Password, ARPrivileges, CPrivileges)
where ARPrivileges means assert/retract permission, while CPrivileges means
call permission.
Privileges could be a list of Module:Functor/Arity elements. For example:
[_:_/_] would mean full "admin"
[lists:_/_, user:_/_] would mean the user is allowed to call
every predicate of modules "lists" and "user"
or anything more complex such as:
[lists:P], memberchk(P, [permutation/2, union/3]), ...
Does this make any sense?
Thank you again.
M
I guess yes, but a runtime check of such a flexible scenario would be a
bit slow. Making a few restrictions on the language and find out the
permissions before you do any calling looks more promising. That is why
I wrote safe_goal(:Goal). The current implementation refuses if it finds
a meta-call for which it cannot figure out what will be called. You
could of course replace call(X) by safe_call(X) in that case and
implement safe_call/1 as:
safe_call(Goal) :-
( safe_goal(Goal)
-> call(Goal)
; permission_error(call, goal, Goal)
).
and likewise for call/2-, assert/1, etc.
Changing the simple safe_goal/1 which is simply based on a white-list
of goals to use a white-list for the current user profile is a simple
change. You can even do (in the current code-base):
save_primitive(assert(_)) :- privileges(admin).
Join the club if you want to break the current safe_goal approach or
want to extend it with facilities you propose.
Cheers --- Jan
1) grant(+Privilege, +To, +On)
Just to give a couple of example:
:- grant(assert, mauro, [user:p/1, user:q/1]).
or:
:- grant(call, public, [system:_]).
Obviously, one should implement also:
2) revoke(+Privilege, +On, +From)
With respect to the checking process, I argue that it would be fruitful to
implement in the interpreter proper. I don't know exactly how (perhaps you
do), but I was thinking to a sort of hidden goals which are automatically
(i.e. transparently to the user) incorporated into every predicate. For
example:
assert(Module:Term) :- current_user(User), current_privilege(assert, User,
P), ... % checking on module/predicate
In other words, do you think that the problem can be solved by means of
external library, or one has to act inside the engine (i.e.
interpreter/compiler) proper?
Thank you.
M
"Jan Wielemaker" <ja...@hppc323.few.vu.nl> wrote in message
news:slrnhmgck...@hppc323.few.vu.nl...
My proposed approach can work as a library (ok, not on all Prolog
implementation, because you need reflexion on all code and ISO only
depands it for dynamic code). The only downside is some limitation
of the language, e.g. it fails if you try this (which could even be
relaxed if enough is known about <something>.
G =.. <something>
call(G).
Your proposal needs either a generally hookable assert/retract (but in
principal any predicate with side-effects) or goal expansion to rewrite
the calls and some way to ensure that the user doesn't bypass the
expanded goal.
I'm not much in favour of a general hook. You can cache analysis
results, so they need not impose a lot of overhead to the application.
Cheers --- Jan
Lack of standardization of Prolog reflection predicates such as
current_predicate/1 and, specially, predicate_property/2 is also
problematic in Logtalk, forcing me to have Prolog-specific hooks to
ensure correct compilation of object predicate clauses. But just to be
clear, your remark above is about using clause/2 (which is also a
reflection predicate) on static predicates?
Cheers,
Paulo
I have substantial difficulties following your discussion. Have you all
read 7.5.3? In this subclause, the notion of private and public procedures
are defined.
In particular, it is said that "a static user-defined procedure shall be
private by default"
^^^^^^^^^^
Also, the non-normative Note suggests to add public/1 as an extension.
This is not necessarily the only way to perform the extension.
Nothing to do with public/private predicates in the sense of object-oriented
data encapsulation.
I argue that it is not possible to have 100% security with an external
library, unless very very very slow (and possibly, unsafe) execution.
As Jan pointed out, consider the following:
...
Atom = 'expand_file_name',
atom_to_term(Atom, Term, _),
G1 =.. [Term, '*', Files],
call(G1),
( select(File, Files, _), ignore(call(once(delete_file(File)))), fail ;
true),
...
I think it is quite impossible to avoid things like this using term/goal
expansion and clause predicates.
How to solve it?
M
"Ulrich Neumerkel" <ulr...@mips.complang.tuwien.ac.at> wrote in message
news:2010Feb...@mips.complang.tuwien.ac.at...
I have.
> In this subclause, the notion of private and public procedures
> are defined.
>
> In particular, it is said that "a static user-defined procedure shall be
> private by default"
> ^^^^^^^^^^
But this sentence doesn't contradict Jan: the ISO Prolog standard only
requires that dynamic predicates can be inspected using clause/2. I
don't see nothing in 7.5.3 that requires a complaint Prolog
implementation to offer more than the default "static predicates are
private". But please correct me if I'm wrong.
> Also, the non-normative Note suggests to add public/1 as an extension.
That would be an unfortunate extension to implement given modules,
objects, or any other kind of encapsulation units. This unfortunate
(name) suggestion found its way in the ISO standard for Prolog modules
where (in section 6.8) the predicate properties "public" and "private"
follows from 7.5.3, meaning , precluding their use for representing
predicate scope.
But the point is, as you probably know, most Prolog implementations
don't support using clause/2 over static predicates (assuming that's
what Jan was talking about; I'm waiting his reply).
Cheers,
Paulo
Why a problem? If you represent each user using a different object,
you have a place to customize the goal-checking code that ensures that
each user specific privileges are respected. The objects representing
the users can inherit the same database. A similar setup might be
possible using modules but I will leave that to others.
> Nothing to do with public/private predicates in the sense of object-oriented
> data encapsulation.
I would say that this would provide you with basic security but thanks
for clarifying what you're after.
> I argue that it is not possible to have 100% security with an external
> library, unless very very very slow (and possibly, unsafe) execution.
Maybe. But I'm not sure that an hypothetic implementation at the
Prolog core level would not hurt the performance of every other
application. I agree with Jan that what the features you want are
better implemented in a library.
Cheers,
Paulo
Yes.
--- Jan
Nice to imagine, but hard to see in practice.
How you can force a user to stay in his/her own "module"... oops "object"?
Do I miss something?
An example would be really appreciated!
>
> Maybe. But I'm not sure that an hypothetic implementation at the
> Prolog core level would not hurt the performance of every other
> application. I agree with Jan that what the features you want are
> better implemented in a library.
Do you think the potential (dis)advantage is the (im)possibility to switch
it off?
In other words, if the issue is just about "performance" you can start your
Prolog system in a sort of "all public" mode, thereby "switching-off" the
goal-checking process.
Anyway, I see your point. But my question is indeed: HOW?
Thanks
M
You are right. But almost 15 years after 13211-1, we could start
to look for possible extensions. Could we not?
>> Also, the non-normative Note suggests to add public/1 as an extension.
>
>That would be an unfortunate extension ...
Agreed, maybe differently.
In your original post, you talked about "Prolog and the Web". I assume
that the queries will be sent to the server together with user
identification (but maybe you're thinking about a completely
scenario?). Thus, the queries would be sent to the object identified
by the user credentials. By wrapping a query as an argument to the
message sent to the user object, keeping a user in its own module
would depend on the implementation (method) of that message. This
method would do all the meta-interpreting needed for the calling
semantics and user-specifc privileges.
> An example would be really appreciated!
Sure. I suggest we work on a simple example by private mail and, when
satisfied with the result, post it back to this newsgroup (but I will
be quite busy with stuff-that-justifies-my-salary until the end of
next week).
> > Maybe. But I'm not sure that an hypothetic implementation at the
> > Prolog core level would not hurt the performance of every other
> > application. I agree with Jan that what the features you want are
> > better implemented in a library.
>
> Do you think the potential (dis)advantage is the (im)possibility to switch
> it off?
> In other words, if the issue is just about "performance" you can start your
> Prolog system in a sort of "all public" mode, thereby "switching-off" the
> goal-checking process.
I just think that this is a too special feature to go into the core,
even with an hypothetical switch turned off by default. The possible
issues here go beyond performance. It would be one more thing to
maintain and the ramifications of such features are not clear for me.
How would such a feature interact with other core features? The
apparent orthogonality of Prolog features at the user abstract level
can quickly evaporate when you dive into the implementation.
Cheers,
Paulo
Except the somewhat unfortunate names private and public, I see no
problem with the specification. Demanding an implementation to be able to
show the original program-terms would harm possibilities for optimization
far too much. Just, if you can provide that feature, it is pretty useful
for enhancing the environment and doing all sorts of analysis on the loaded
program rather than the source.
--- Jan