Support » Developing with WordPress » Secure my plugin

  • Resolved mortenamdk

    (@mortenamdk)


    Hi there

    I have some questions about nonce function.
    How do I make that, and how do I best secure I best the plugin.

    Have made a plugin to make a top banner, where I have a insert update delete function in ajax.

    I have made my database like this:

    id int(10) unsigned NOT NULL AUTO_INCREMENT,
              (hidden)_top_banner_name varchar(255) NOT NULL,
              (hidden)_top_banner_name_color varchar(20) NOT NULL,
              (hidden)_top_banner_name_top_height varchar(10) NOT NULL,
              (hidden)_top_banner_name_top_text_line varchar(3) NOT NULL,
              (hidden)_top_banner_name_top_start_date varchar(10) NOT NULL,
              (hidden)_top_banner_name_top_stop_date varchar(10) NOT NULL,
              (hidden)_top_banner_name_media varchar(255) NOT NULL,
              (hidden)_image_attachment_id int(10) NOT NULL,
              PRIMARY KEY  (<code>id</code>)

    So there is no possibility of too many characters, but have i am not so good to it, it is my first plugin i have made.

    Here is some code to se my ajax handler:

    function ajax_(hidden)_insert_top_banner() {
    
        // The $_REQUEST contains all the data sent via ajax
        global $wpdb;
          $table_name = $wpdb->prefix . "topbanner";
        if ( isset($_REQUEST) ) {
    
            $(hidden)_top_banner_name                  = wp_kses_post($_REQUEST['(hidden)_top_banner_name']);
            $(hidden)_top_banner_name_color            = sanitize_hex_color($_REQUEST['(hidden)_top_banner_name_color']);
            $(hidden)_top_banner_name_top_text_line    = sanitize_text_field($_REQUEST['(hidden)_top_banner_name_top_text_line']);
            $(hidden)_top_banner_name_top_height       = sanitize_text_field($_REQUEST['(hidden)_top_banner_name_top_height']);
            $(hidden)_top_banner_name_top_start_date   = sanitize_text_field($_REQUEST['(hidden)_top_banner_name_top_start_date']);
            $(hidden)_top_banner_name_top_stop_date    = sanitize_text_field($_REQUEST['(hidden)_top_banner_name_top_stop_date']);
            $(hidden)_top_banner_name_media            = sanitize_text_field($_REQUEST['(hidden)_top_banner_name_media']);
            $(hidden)_image_attachment_id              = sanitize_text_field($_REQUEST['(hidden)_image_attachment_id']);
    
        $wpdb->query($wpdb->prepare(
        	"
        		INSERT INTO $table_name
                ( (hidden)_top_banner_name, (hidden)_top_banner_name_color, (hidden)_top_banner_name_top_text_line, (hidden)_top_banner_name_top_height, (hidden)_top_banner_name_top_start_date, (hidden)_top_banner_name_top_stop_date, (hidden)_top_banner_name_media, (hidden)_image_attachment_id )
        		VALUES ( %s, %s, %s, %s, %s, %s, %s, %d )
        	",
            array(
                $(hidden)_top_banner_name,
                $(hidden)_top_banner_name_color,
                $(hidden)_top_banner_name_top_text_line,
                $(hidden)_top_banner_name_top_height,
                $(hidden)_top_banner_name_top_start_date,
                $(hidden)_top_banner_name_top_stop_date,
                $(hidden)_top_banner_name_media,
                $(hidden)_image_attachment_id
                )
        )
    
        );
        }
    
        // Always die in functions echoing ajax content
       die();
    }
    
    add_action( 'wp_ajax_ajax_(hidden)_insert_top_banner', 'ajax_(hidden)_insert_top_banner' );

    And here is the js:

    (function($) {
     $(document).on('click', '#insert_submit', function (e) {
       e.preventDefault();
           // We'll pass this variable to the PHP function example_ajax_request
           var (hidden)_top_banner_name = tinymce.get('(hidden)_top_banner_name').getContent();
           var (hidden)_top_banner_name_color = $('#(hidden)_top_banner_name_color').val();
           var (hidden)_top_banner_name_top_text_line = $('#(hidden)_top_banner_name_top_text_line').val();
           var (hidden)_top_banner_name_top_height = $('#(hidden)_top_banner_name_top_height').val();
           var (hidden)_top_banner_name_top_start_date = $('#(hidden)_top_banner_name_top_start_date').val();
           var (hidden)_top_banner_name_top_stop_date = $('#(hidden)_top_banner_name_top_stop_date').val();
           var (hidden)_top_banner_name_media = $('#(hidden)_top_banner_name_media').val();
           var (hidden)_image_attachment_id = $('#(hidden)_image_attachment_id').val();
           // This does the ajax request
           $.ajax({
               url: (hidden)_ajax_obj.ajaxurl, // or example_ajax_obj.ajaxurl if using on frontend
               data: {
                   'action': 'ajax_(hidden)_insert_top_banner',
                   '(hidden)_top_banner_name' : (hidden)_top_banner_name,
                   '(hidden)_top_banner_name_color' : (hidden)_top_banner_name_color,
                   '(hidden)_top_banner_name_top_text_line' : (hidden)_top_banner_name_top_text_line,
                   '(hidden)_top_banner_name_top_height' : (hidden)_top_banner_name_top_height,
                   '(hidden)_top_banner_name_top_start_date' : (hidden)_top_banner_name_top_start_date,
                   '(hidden)_top_banner_name_top_stop_date' : (hidden)_top_banner_name_top_stop_date,
                   '(hidden)_top_banner_name_media' : (hidden)_top_banner_name_media,
                   '(hidden)_image_attachment_id' : (hidden)_image_attachment_id,
               },
               success:function(data) {
                   // This outputs the result of the ajax request
                   console.log(data);
               },
               complete:function(data){
                   location.reload();
               },
               error: function(errorThrown){
                   console.log(errorThrown);
               }
           });
    
       });
    
    })(jQuery);
    	wp_enqueue_script(
    		'(hidden)-ajax-script',
    		plugin_dir_url( __FILE__ ) . '/js/ajax_insert.js',
    		array('jquery')
    	);
    	// The wp_localize_script allows us to output the ajax_url path for our script to use.
    	wp_localize_script(
    		'(hidden)-ajax-script',
    		'(hidden)_ajax_obj',
    		array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) )
    	);

    Best regards
    Morten

    The page I need help with: [log in to see the link]

Viewing 3 replies - 1 through 3 (of 3 total)
  • Moderator Tellyworth

    (@tellyworth)

    This explains how to create a nonce and pass it to Javascript via wp_localize_script():

    https://developer.wordpress.org/plugins/javascript/enqueuing/#nonce

    Read the following sections also about Localize, Ajax Action and so on.

    Also, it’s generally better to avoid creating a custom SQL table, and instead store your data in postmeta, custom post types, or options. WordPress already has built in post types for attachments that might suit your needs. You’ll find those things well documented in the Plugin Handbook.

    Moderator bcworkz

    (@bcworkz)

    Tellyworth’s link is a good reference (disclaimer: I contributed to the writing of the linked Ajax pages 🙂 ) There is an important note that covers those pages that kinda got lost on a different page:

    Note: This code snippet, and all examples on this page, are for illustrating the use of AJAX. The code is not suitable for production environments because related operations such as sanitization, security, error handling, and internationalization have been intentionally omitted. Be sure to always address these important operations in your production code.

    Checking the nonce and Ajax referrer is covered in the examples. When the DB is being updated by handler code, you should likely be also verifying user capability. For example:

    if ( ! current_user_can('manage_options')) { echo 'Error. You do not have adequate user capability to do this'; exit; }
    //proceed with update

    Sanitation and validation is broad topic as the solution depends on the nature of the data. See https://code.tutsplus.com/articles/data-sanitization-and-validation-with-wordpress–wp-25536

    A little off topic, but I agree that the meta tables are generally preferable to a custom SQL table. Up to a point. If you are frequently making queries that involve complex meta data relationships which involve large amounts of data, WP meta queries can be slow and inefficient and a custom table may be justified for efficiency and speed reasons.

    Hello you two

    Thanks for the answers, it helps me well on my way.
    And thank you bcworkz, for all that work in getting me on the right track with my project.
    I will at least do what I can to get the plugin secure with your help.

    Thanks for now 🙂

    Best regards
    Morten

Viewing 3 replies - 1 through 3 (of 3 total)
  • You must be logged in to reply to this topic.