You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cordova.apache.org by "Terence M. Bandoian" <te...@tmbsw.com> on 2014/06/02 04:20:22 UTC
Re: Android Plugin API
It does get complicated in a hurry. Using the technique in the Google
Maps plugin:
- getDeclaredMethod is documented to NOT return inherited methods which
limits exposure
- the signature passed to getDeclaredMethod also limits exposure
- annotations, as Andrew suggested, could further limit exposure
- getDeclaredMethod is documented to return private methods which for me
raises questions
- setAccessible(true) suppresses normal access checking which also
raises questions
- invoke throws InvocationTargetException so exceptions thrown by the
invoked method could be publicized
- invoke applies overriding which is probably a wash
- invoke returns an object which would have to be handled correctly
Quite a bit to consider.
-Terence Bandoian
On 5/29/2014 11:44 PM, Joe Bowser wrote:
> On Thu, May 29, 2014 at 9:26 PM, Terence M. Bandoian <te...@tmbsw.com> wrote:
>> Please correct me if I'm wrong but, as I understand it, the vulnerability
>> stems from injecting a Java object into the WebView which, in API levels 16
>> and below, exposed all of the public methods of the object (small 'o')
>> including the methods inherited from the Object class.
>>
> Yes, you are correct in this case. You can basically use the object
> methods to reflect into whatever you want. Once you have a single
> class exposed in this manner, you can then reflect into it, and
> basically you're done. The reason we don't use reflection is that
> it's very easy to reflect into things you're not supposed to be in.
> IMO, It wouldn't be hard to do this if we exposed plugins in the same
> way. Right now this is an Android Vulnerability, but if we start
> using reflection for plugins, we could very quickly end up making a
> similar Cordova exploit if we're not careful.
>
> This is also why we use the prompt bridge on API levels below 17.
>
>>
>>
>> On 5/28/2014 9:54 AM, Joe Bowser wrote:
>>> In case anyone is curious, here's why we minimize reflection:
>>>
>>>
>>> https://labs.mwrinfosecurity.com/blog/2013/09/24/webview-addjavascriptinterface-remote-code-execution/
>>>
>>> On Wed, May 28, 2014 at 7:33 AM, Andrew Grieve <ag...@chromium.org>
>>> wrote:
>>>> Another reasonable approach would be to use a Map<String, Runnable>, but
>>>> that can be implemented on top of what is currently exposed. I'm quite
>>>> wary
>>>> of Reflection as well.
>>>>
>>>>
>>>> On Wed, May 28, 2014 at 10:06 AM, Joe Bowser <bo...@gmail.com> wrote:
>>>>
>>>>> The execute command exists for security reasons. We don't want any
>>>>> methods other than execute exposed to Javascript. I also prefer this
>>>>> approach because it is less prone to less catastrophic bugs than using
>>>>> Java reflection. We try and only use reflection when we have to.
>>>>>
>>>>> On Wed, May 28, 2014 at 5:50 AM, Erik Jan de Wit <ed...@redhat.com>
>>>>> wrote:
>>>>>> Hi,
>>>>>>
>>>>>> When one is writing a plugin for android ATM the api that you have to
>>>>> implement has a execute method that has the action as a string:
>>>>>> @Override
>>>>>> public boolean execute(String action, JSONArray args,
>>>>> CallbackContext callbackContext) throws JSONException {
>>>>>> if ("beep".equals(action)) {
>>>>>> this.beep(args.getLong(0));
>>>>>> callbackContext.success();
>>>>>> return true;
>>>>>> }
>>>>>> return false; // Returning false results in a
>>>>>> "MethodNotFound"
>>>>> error.
>>>>>> }
>>>>>> When you have multiple actions this method gets very long, if you
>>>>> compare this with iOS here you don’t need a method like this you could
>>>>> ‘just’ implement the method directly:
>>>>>> - (void)beep:(CDVInvokedUrlCommand*)command
>>>>>> {
>>>>>> CDVPluginResult* pluginResult =;
>>>>>> NSString* myarg =mmand.arguments objectAtIndex:0];
>>>>>>
>>>>>> if (myarg !=) {
>>>>>> pluginResult �VPluginResult
>>>>> resultWithStatus:CDVCommandStatus_OK];
>>>>>> } else {
>>>>>> pluginResult �VPluginResult
>>>>> resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Arg was
>>>>> null"];
>>>>>> }
>>>>>> [self.commandDelegate sendPluginResult:pluginResult
>>>>> callbackId:command.callbackId];
>>>>>> }
>>>>>> We could do the same thing for android if we use reflection, making the
>>>>> API more similar and removing all the string test by the user. What do
>>>>> you
>>>>> think?
>>>>>> Cheers,
>>>>>> Erik Jan
>>
Re: Android Plugin API
Posted by Joe Bowser <bo...@gmail.com>.
We won't be breaking plugins. I don't want to move to this for the reasons
stated before. This code also is way less maintainable, and looks like it
could break easily. I really think that clarity should win out here over
an abuse of java reflection.
On 10 Jul,2014, at 17:15 , Anis KADRI <an...@gmail.com> wrote:
> I want to say that this should be default...but we won't change the API
> again and won't break plugins again.
Both could be supported at the same time, just by using a different base
class
Re: Android Plugin API
Posted by Erik Jan de Wit <ed...@redhat.com>.
On 10 Jul,2014, at 17:15 , Anis KADRI <an...@gmail.com> wrote:
> I want to say that this should be default...but we won't change the API
> again and won't break plugins again.
Both could be supported at the same time, just by using a different base class
Re: Android Plugin API
Posted by Anis KADRI <an...@gmail.com>.
I want to say that this should be default...but we won't change the API
again and won't break plugins again.
On Thu, Jul 10, 2014 at 7:48 AM, Erik Jan de Wit <ed...@redhat.com> wrote:
> Hi all,
>
> Created an plugin that does this:
> https://github.com/edewit/aerogear-reflect-cordova the repository also
> includes a example plugin that uses this. Also have a blog describing this
> a bit more
> http://blog.nerdin.ch/2014/07/improved-cordova-android-plugin-api.html
>
> Cheers,
> Erik Jan
>
> On 2 Jun,2014, at 4:20 , Terence M. Bandoian <te...@tmbsw.com> wrote:
>
> > It does get complicated in a hurry. Using the technique in the Google
> Maps plugin:
> >
> > - getDeclaredMethod is documented to NOT return inherited methods which
> limits exposure
> > - the signature passed to getDeclaredMethod also limits exposure
> > - annotations, as Andrew suggested, could further limit exposure
> >
> > - getDeclaredMethod is documented to return private methods which for me
> raises questions
> > - setAccessible(true) suppresses normal access checking which also
> raises questions
> >
> > - invoke throws InvocationTargetException so exceptions thrown by the
> invoked method could be publicized
> > - invoke applies overriding which is probably a wash
> > - invoke returns an object which would have to be handled correctly
> >
> > Quite a bit to consider.
> >
> > -Terence Bandoian
> >
> >
> > On 5/29/2014 11:44 PM, Joe Bowser wrote:
> >> On Thu, May 29, 2014 at 9:26 PM, Terence M. Bandoian <te...@tmbsw.com>
> wrote:
> >>> Please correct me if I'm wrong but, as I understand it, the
> vulnerability
> >>> stems from injecting a Java object into the WebView which, in API
> levels 16
> >>> and below, exposed all of the public methods of the object (small 'o')
> >>> including the methods inherited from the Object class.
> >>>
> >> Yes, you are correct in this case. You can basically use the object
> >> methods to reflect into whatever you want. Once you have a single
> >> class exposed in this manner, you can then reflect into it, and
> >> basically you're done. The reason we don't use reflection is that
> >> it's very easy to reflect into things you're not supposed to be in.
> >> IMO, It wouldn't be hard to do this if we exposed plugins in the same
> >> way. Right now this is an Android Vulnerability, but if we start
> >> using reflection for plugins, we could very quickly end up making a
> >> similar Cordova exploit if we're not careful.
> >>
> >> This is also why we use the prompt bridge on API levels below 17.
> >>
> >>>
> >>>
> >>> On 5/28/2014 9:54 AM, Joe Bowser wrote:
> >>>> In case anyone is curious, here's why we minimize reflection:
> >>>>
> >>>>
> >>>>
> https://labs.mwrinfosecurity.com/blog/2013/09/24/webview-addjavascriptinterface-remote-code-execution/
> >>>>
> >>>> On Wed, May 28, 2014 at 7:33 AM, Andrew Grieve <ag...@chromium.org>
> >>>> wrote:
> >>>>> Another reasonable approach would be to use a Map<String, Runnable>,
> but
> >>>>> that can be implemented on top of what is currently exposed. I'm
> quite
> >>>>> wary
> >>>>> of Reflection as well.
> >>>>>
> >>>>>
> >>>>> On Wed, May 28, 2014 at 10:06 AM, Joe Bowser <bo...@gmail.com>
> wrote:
> >>>>>
> >>>>>> The execute command exists for security reasons. We don't want any
> >>>>>> methods other than execute exposed to Javascript. I also prefer
> this
> >>>>>> approach because it is less prone to less catastrophic bugs than
> using
> >>>>>> Java reflection. We try and only use reflection when we have to.
> >>>>>>
> >>>>>> On Wed, May 28, 2014 at 5:50 AM, Erik Jan de Wit <edewit@redhat.com
> >
> >>>>>> wrote:
> >>>>>>> Hi,
> >>>>>>>
> >>>>>>> When one is writing a plugin for android ATM the api that you have
> to
> >>>>>> implement has a execute method that has the action as a string:
> >>>>>>> @Override
> >>>>>>> public boolean execute(String action, JSONArray args,
> >>>>>> CallbackContext callbackContext) throws JSONException {
> >>>>>>> if ("beep".equals(action)) {
> >>>>>>> this.beep(args.getLong(0));
> >>>>>>> callbackContext.success();
> >>>>>>> return true;
> >>>>>>> }
> >>>>>>> return false; // Returning false results in a
> >>>>>>> "MethodNotFound"
> >>>>>> error.
> >>>>>>> }
> >>>>>>> When you have multiple actions this method gets very long, if you
> >>>>>> compare this with iOS here you don’t need a method like this you
> could
> >>>>>> ‘just’ implement the method directly:
> >>>>>>> - (void)beep:(CDVInvokedUrlCommand*)command
> >>>>>>> {
> >>>>>>> CDVPluginResult* pluginResult =;
> >>>>>>> NSString* myarg =mmand.arguments objectAtIndex:0];
> >>>>>>>
> >>>>>>> if (myarg !=) {
> >>>>>>> pluginResult �VPluginResult
> >>>>>> resultWithStatus:CDVCommandStatus_OK];
> >>>>>>> } else {
> >>>>>>> pluginResult �VPluginResult
> >>>>>> resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Arg was
> >>>>>> null"];
> >>>>>>> }
> >>>>>>> [self.commandDelegate sendPluginResult:pluginResult
> >>>>>> callbackId:command.callbackId];
> >>>>>>> }
> >>>>>>> We could do the same thing for android if we use reflection,
> making the
> >>>>>> API more similar and removing all the string test by the user. What
> do
> >>>>>> you
> >>>>>> think?
> >>>>>>> Cheers,
> >>>>>>> Erik Jan
>
>
Re: Android Plugin API
Posted by Erik Jan de Wit <ed...@redhat.com>.
Hi all,
Created an plugin that does this: https://github.com/edewit/aerogear-reflect-cordova the repository also includes a example plugin that uses this. Also have a blog describing this a bit more http://blog.nerdin.ch/2014/07/improved-cordova-android-plugin-api.html
Cheers,
Erik Jan
On 2 Jun,2014, at 4:20 , Terence M. Bandoian <te...@tmbsw.com> wrote:
> It does get complicated in a hurry. Using the technique in the Google Maps plugin:
>
> - getDeclaredMethod is documented to NOT return inherited methods which limits exposure
> - the signature passed to getDeclaredMethod also limits exposure
> - annotations, as Andrew suggested, could further limit exposure
>
> - getDeclaredMethod is documented to return private methods which for me raises questions
> - setAccessible(true) suppresses normal access checking which also raises questions
>
> - invoke throws InvocationTargetException so exceptions thrown by the invoked method could be publicized
> - invoke applies overriding which is probably a wash
> - invoke returns an object which would have to be handled correctly
>
> Quite a bit to consider.
>
> -Terence Bandoian
>
>
> On 5/29/2014 11:44 PM, Joe Bowser wrote:
>> On Thu, May 29, 2014 at 9:26 PM, Terence M. Bandoian <te...@tmbsw.com> wrote:
>>> Please correct me if I'm wrong but, as I understand it, the vulnerability
>>> stems from injecting a Java object into the WebView which, in API levels 16
>>> and below, exposed all of the public methods of the object (small 'o')
>>> including the methods inherited from the Object class.
>>>
>> Yes, you are correct in this case. You can basically use the object
>> methods to reflect into whatever you want. Once you have a single
>> class exposed in this manner, you can then reflect into it, and
>> basically you're done. The reason we don't use reflection is that
>> it's very easy to reflect into things you're not supposed to be in.
>> IMO, It wouldn't be hard to do this if we exposed plugins in the same
>> way. Right now this is an Android Vulnerability, but if we start
>> using reflection for plugins, we could very quickly end up making a
>> similar Cordova exploit if we're not careful.
>>
>> This is also why we use the prompt bridge on API levels below 17.
>>
>>>
>>>
>>> On 5/28/2014 9:54 AM, Joe Bowser wrote:
>>>> In case anyone is curious, here's why we minimize reflection:
>>>>
>>>>
>>>> https://labs.mwrinfosecurity.com/blog/2013/09/24/webview-addjavascriptinterface-remote-code-execution/
>>>>
>>>> On Wed, May 28, 2014 at 7:33 AM, Andrew Grieve <ag...@chromium.org>
>>>> wrote:
>>>>> Another reasonable approach would be to use a Map<String, Runnable>, but
>>>>> that can be implemented on top of what is currently exposed. I'm quite
>>>>> wary
>>>>> of Reflection as well.
>>>>>
>>>>>
>>>>> On Wed, May 28, 2014 at 10:06 AM, Joe Bowser <bo...@gmail.com> wrote:
>>>>>
>>>>>> The execute command exists for security reasons. We don't want any
>>>>>> methods other than execute exposed to Javascript. I also prefer this
>>>>>> approach because it is less prone to less catastrophic bugs than using
>>>>>> Java reflection. We try and only use reflection when we have to.
>>>>>>
>>>>>> On Wed, May 28, 2014 at 5:50 AM, Erik Jan de Wit <ed...@redhat.com>
>>>>>> wrote:
>>>>>>> Hi,
>>>>>>>
>>>>>>> When one is writing a plugin for android ATM the api that you have to
>>>>>> implement has a execute method that has the action as a string:
>>>>>>> @Override
>>>>>>> public boolean execute(String action, JSONArray args,
>>>>>> CallbackContext callbackContext) throws JSONException {
>>>>>>> if ("beep".equals(action)) {
>>>>>>> this.beep(args.getLong(0));
>>>>>>> callbackContext.success();
>>>>>>> return true;
>>>>>>> }
>>>>>>> return false; // Returning false results in a
>>>>>>> "MethodNotFound"
>>>>>> error.
>>>>>>> }
>>>>>>> When you have multiple actions this method gets very long, if you
>>>>>> compare this with iOS here you don’t need a method like this you could
>>>>>> ‘just’ implement the method directly:
>>>>>>> - (void)beep:(CDVInvokedUrlCommand*)command
>>>>>>> {
>>>>>>> CDVPluginResult* pluginResult =;
>>>>>>> NSString* myarg =mmand.arguments objectAtIndex:0];
>>>>>>>
>>>>>>> if (myarg !=) {
>>>>>>> pluginResult �VPluginResult
>>>>>> resultWithStatus:CDVCommandStatus_OK];
>>>>>>> } else {
>>>>>>> pluginResult �VPluginResult
>>>>>> resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Arg was
>>>>>> null"];
>>>>>>> }
>>>>>>> [self.commandDelegate sendPluginResult:pluginResult
>>>>>> callbackId:command.callbackId];
>>>>>>> }
>>>>>>> We could do the same thing for android if we use reflection, making the
>>>>>> API more similar and removing all the string test by the user. What do
>>>>>> you
>>>>>> think?
>>>>>>> Cheers,
>>>>>>> Erik Jan