Android 剪切板敏感信息泄露漏洞解决:禁用EditText的复制粘贴功能

Android 中任何第三方软件都可访问剪切板内容,虽然高版本对剪切板做了访问限制,但是还是需要照顾一下低版本的,解决方法就是要禁用复制剪切选项。下边来看具体实现吧。

1、自定义NoMenuEditText 继承自AppCompatEditText

2、重写isSuggestionsEnabled方法并返回false

     创建canPaste()方法并返回false。该方法是一个隐藏方法

3、实现ActionMode.Callback回调

 private class ActionModeCallbackInterceptor implements ActionMode.Callback {

        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            //删除复制选项
            MenuItem itemCopy = menu.findItem(android.R.id.copy);
            if (itemCopy != null) {
                menu.removeItem(android.R.id.copy);
            }
            //删除剪切选项
            MenuItem itemCut = menu.findItem(android.R.id.cut);
            if (itemCut != null) {
                menu.removeItem(android.R.id.cut);
            }
            return true;
        }

        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        public void onDestroyActionMode(ActionMode mode) {
        }
    }

4、设置回调

      this.setLongClickable(false);
        //this.setTextIsSelectable(false);
        this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
        //使用该方式基本可以实现禁用粘贴复制功能,6.0以上可用
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            this.setCustomInsertionActionModeCallback(new ActionModeCallbackInterceptor());
        }

使用以上方式即可禁用掉EditText的复制粘贴功能,但是长按EditTeit控件中的文本时光标会有变化,并且该方式只能在6.0以上版本中使用。如果以上方式不能满足你的需求,请看以下方式:

1、2、3步同上,修改第4步不再用 this.setCustomInsertionActionModeCallback(new ActionModeCallbackInterceptor())方法。

使用以下方式(反射)代替:

 this.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                NoMenuEditText.this.clearFocus();
                return false;
            }
        });
@SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // setInsertionDisabled when user touches the view
            this.setInsertionDisabled();
        }
        return super.onTouchEvent(event);
    }

    private void setInsertionDisabled() {
        try {
            Field editorField = TextView.class.getDeclaredField("mEditor");
            editorField.setAccessible(true);
            Object editorObject = editorField.get(this);

            @SuppressLint("PrivateApi") Class editorClass = Class.forName("android.widget.Editor");
            Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
            mInsertionControllerEnabledField.setAccessible(true);
            mInsertionControllerEnabledField.set(editorObject, false);
        } catch (Exception ignored) {
        }
    }

使用这种方式即可解决第一种方式的版本兼容问题,并且长按EditText控件中的文本光标也不会有任何变化,完美解决剪切板敏感信息泄露问题。希望以上方案对你有所帮助。

完整代码(别忘了点个赞哦):

@SuppressLint("NewApi")
public class NoMenuEditText extends AppCompatEditText {
    private final Context context;

    /**
     * 该方法为隐藏方法
     */
    boolean canPaste() {
        return false;
    }

    @Override
    public boolean isSuggestionsEnabled() {
        return false;
    }

    public NoMenuEditText(Context context) {
        super(context);
        this.context = context;
        init();
    }

    public NoMenuEditText(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.context = context;
        init();
    }

    public NoMenuEditText(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.context = context;
        init();
    }

    @SuppressLint("ClickableViewAccessibility")
    private void init() {
        this.setLongClickable(false);
        //this.setTextIsSelectable(false);
        this.setCustomSelectionActionModeCallback(new ActionModeCallbackInterceptor());
        //使用该方式基本可以实现禁用粘贴复制功能,6.0以上可用
//        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
//            this.setCustomInsertionActionModeCallback(new ActionModeCallbackInterceptor());
//        }
        this.setOnTouchListener(new OnTouchListener() {
            @Override
            public boolean onTouch(View v, MotionEvent event) {
                NoMenuEditText.this.clearFocus();
                return false;
            }
        });
    }

    @SuppressLint("ClickableViewAccessibility")
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            // setInsertionDisabled when user touches the view
            this.setInsertionDisabled();
        }
        return super.onTouchEvent(event);
    }

    private void setInsertionDisabled() {
        try {
            Field editorField = TextView.class.getDeclaredField("mEditor");
            editorField.setAccessible(true);
            Object editorObject = editorField.get(this);

            @SuppressLint("PrivateApi") Class editorClass = Class.forName("android.widget.Editor");
            Field mInsertionControllerEnabledField = editorClass.getDeclaredField("mInsertionControllerEnabled");
            mInsertionControllerEnabledField.setAccessible(true);
            mInsertionControllerEnabledField.set(editorObject, false);
        } catch (Exception ignored) {
        }
    }

    /**
     * Prevents the action bar (top horizontal bar with cut,copy,paste,etc.)
     * from appearing by intercepting the callback that would cause it to be
     * created,and returning false.
     */
    private class ActionModeCallbackInterceptor implements ActionMode.Callback {

        public boolean onCreateActionMode(ActionMode mode, Menu menu) {
            //删除复制选项
            MenuItem itemCopy = menu.findItem(android.R.id.copy);
            if (itemCopy != null) {
                menu.removeItem(android.R.id.copy);
            }
            //删除剪切选项
            MenuItem itemCut = menu.findItem(android.R.id.cut);
            if (itemCut != null) {
                menu.removeItem(android.R.id.cut);
            }
            return true;
        }

        public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
            return false;
        }

        public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
            return false;
        }

        public void onDestroyActionMode(ActionMode mode) {
        }
    }
}

参考:https://stackoverflow.com/questions/41673185/disable-edittext-context-menu

你可能感兴趣的:(个人笔记,android,EditText,禁用EditText复制粘贴)